/* * COPYRIGHT (c) 1988-1994 BY * * PARADIGM ASSOCIATES INCORPORATED, CAMBRIDGE, MASSACHUSETTS. * * See the source file SLIB.C for more information. * Array-hacking code moved to another source file. */ #include #include #include #include #include #include #include #include "siod.h" #include "siodp.h" static void init_sliba_version (void) { setvar (cintern ("*sliba-version*"), cintern ("$Id$"), NIL); } static LISP sym_plists = NIL; static LISP bashnum = NIL; static LISP sym_e = NIL; static LISP sym_f = NIL; void init_storage_a1 (long type) { long j; struct user_type_hooks *p; set_gc_hooks (type, array_gc_relocate, array_gc_mark, array_gc_scan, array_gc_free, &j); set_print_hooks (type, array_prin1); p = get_user_type_hooks (type); p->fast_print = array_fast_print; p->fast_read = array_fast_read; p->equal = array_equal; p->c_sxhash = array_sxhash; } void init_storage_a (void) { gc_protect (&bashnum); bashnum = newcell (tc_flonum); init_storage_a1 (tc_string); init_storage_a1 (tc_double_array); init_storage_a1 (tc_long_array); init_storage_a1 (tc_lisp_array); init_storage_a1 (tc_byte_array); } LISP array_gc_relocate (LISP ptr) { LISP nw; if ((nw = heap) >= heap_end) gc_fatal_error (); heap = nw + 1; memcpy (nw, ptr, sizeof (struct obj)); return (nw); } void array_gc_scan (LISP ptr) { long j; if TYPEP (ptr, tc_lisp_array) for (j = 0; j < ptr->storage_as.lisp_array.dim; ++j) ptr->storage_as.lisp_array.data[j] = gc_relocate (ptr->storage_as.lisp_array.data[j]); } LISP array_gc_mark (LISP ptr) { long j; if TYPEP (ptr, tc_lisp_array) for (j = 0; j < ptr->storage_as.lisp_array.dim; ++j) gc_mark (ptr->storage_as.lisp_array.data[j]); return (NIL); } void array_gc_free (LISP ptr) { switch (ptr->type) { case tc_string: case tc_byte_array: free (ptr->storage_as.string.data); break; case tc_double_array: free (ptr->storage_as.double_array.data); break; case tc_long_array: free (ptr->storage_as.long_array.data); break; case tc_lisp_array: free (ptr->storage_as.lisp_array.data); break; } } void array_prin1 (LISP ptr, struct gen_printio *f) { int j; switch (ptr->type) { case tc_string: gput_st (f, "\""); if (strcspn (ptr->storage_as.string.data, "\"\\\n\r\t") == strlen (ptr->storage_as.string.data)) gput_st (f, ptr->storage_as.string.data); else { int n, c; char cbuff[3]; n = strlen (ptr->storage_as.string.data); for (j = 0; j < n; ++j) switch (c = ptr->storage_as.string.data[j]) { case '\\': case '"': cbuff[0] = '\\'; cbuff[1] = c; cbuff[2] = 0; gput_st (f, cbuff); break; case '\n': gput_st (f, "\\n"); break; case '\r': gput_st (f, "\\r"); break; case '\t': gput_st (f, "\\t"); break; default: cbuff[0] = c; cbuff[1] = 0; gput_st (f, cbuff); break; } } gput_st (f, "\""); break; case tc_double_array: gput_st (f, "#("); for (j = 0; j < ptr->storage_as.double_array.dim; ++j) { sprintf (tkbuffer, "%g", ptr->storage_as.double_array.data[j]); gput_st (f, tkbuffer); if ((j + 1) < ptr->storage_as.double_array.dim) gput_st (f, " "); } gput_st (f, ")"); break; case tc_long_array: gput_st (f, "#("); for (j = 0; j < ptr->storage_as.long_array.dim; ++j) { sprintf (tkbuffer, "%ld", ptr->storage_as.long_array.data[j]); gput_st (f, tkbuffer); if ((j + 1) < ptr->storage_as.long_array.dim) gput_st (f, " "); } gput_st (f, ")"); case tc_byte_array: sprintf (tkbuffer, "#%ld\"", ptr->storage_as.string.dim); gput_st (f, tkbuffer); for (j = 0; j < ptr->storage_as.string.dim; ++j) { sprintf (tkbuffer, "%02x", ptr->storage_as.string.data[j] & 0xFF); gput_st (f, tkbuffer); } gput_st (f, "\""); break; case tc_lisp_array: gput_st (f, "#("); for (j = 0; j < ptr->storage_as.lisp_array.dim; ++j) { lprin1g (ptr->storage_as.lisp_array.data[j], f); if ((j + 1) < ptr->storage_as.lisp_array.dim) gput_st (f, " "); } gput_st (f, ")"); break; } } LISP strcons (long length, char *data) { long flag; LISP s; flag = no_interrupt (1); s = cons (NIL, NIL); s->type = tc_string; if (length == -1) length = strlen (data); s->storage_as.string.data = must_malloc (length + 1); s->storage_as.string.dim = length; if (data) memcpy (s->storage_as.string.data, data, length); s->storage_as.string.data[length] = 0; no_interrupt (flag); return (s); } int rfs_getc (unsigned char **p) { int i; i = **p; if (!i) return (EOF); *p = *p + 1; return (i); } void rfs_ungetc (unsigned char c, unsigned char **p) { *p = *p - 1; } LISP read_from_string (LISP x) { char *p; struct gen_readio s; p = get_c_string (x); s.getc_fcn = (int (*)(void *)) rfs_getc; s.ungetc_fcn = (void (*)(int, void *)) rfs_ungetc; s.cb_argument = (char *) &p; return (readtl (&s)); } int pts_puts (char *from, void *cb) { LISP into; size_t fromlen, intolen, intosize, fitsize; into = (LISP) cb; fromlen = strlen (from); intolen = strlen (into->storage_as.string.data); intosize = into->storage_as.string.dim - intolen; fitsize = (fromlen < intosize) ? fromlen : intosize; memcpy (&into->storage_as.string.data[intolen], from, fitsize); into->storage_as.string.data[intolen + fitsize] = 0; if (fitsize < fromlen) my_err ("print to string overflow", NIL); return (1); } LISP err_wta_str (LISP exp) { return (my_err ("not a string", exp)); } LISP print_to_string (LISP exp, LISP str, LISP nostart) { struct gen_printio s; if NTYPEP (str, tc_string) err_wta_str (str); s.putc_fcn = NULL; s.puts_fcn = pts_puts; s.cb_argument = str; if NULLP (nostart) str->storage_as.string.data[0] = 0; lprin1g (exp, &s); return (str); } LISP aref1 (LISP a, LISP i) { long k; if NFLONUMP (i) my_err ("bad index to aref", i); k = (long) FLONM (i); if (k < 0) my_err ("negative index to aref", i); switch TYPE (a) { case tc_string: case tc_byte_array: if (k >= a->storage_as.string.dim) my_err ("index too large", i); return (flocons ((double) a->storage_as.string.data[k])); case tc_double_array: if (k >= a->storage_as.double_array.dim) my_err ("index too large", i); return (flocons (a->storage_as.double_array.data[k])); case tc_long_array: if (k >= a->storage_as.long_array.dim) my_err ("index too large", i); return (flocons (a->storage_as.long_array.data[k])); case tc_lisp_array: if (k >= a->storage_as.lisp_array.dim) my_err ("index too large", i); return (a->storage_as.lisp_array.data[k]); default: return (my_err ("invalid argument to aref", a)); } } void err1_aset1 (LISP i) { my_err ("index to aset too large", i); } void err2_aset1 (LISP v) { my_err ("bad value to store in array", v); } LISP aset1 (LISP a, LISP i, LISP v) { long k; if NFLONUMP (i) my_err ("bad index to aset", i); k = (long) FLONM (i); if (k < 0) my_err ("negative index to aset", i); switch TYPE (a) { case tc_string: case tc_byte_array: if NFLONUMP (v) err2_aset1 (v); if (k >= a->storage_as.string.dim) err1_aset1 (i); a->storage_as.string.data[k] = (char) FLONM (v); return (v); case tc_double_array: if NFLONUMP (v) err2_aset1 (v); if (k >= a->storage_as.double_array.dim) err1_aset1 (i); a->storage_as.double_array.data[k] = FLONM (v); return (v); case tc_long_array: if NFLONUMP (v) err2_aset1 (v); if (k >= a->storage_as.long_array.dim) err1_aset1 (i); a->storage_as.long_array.data[k] = (long) FLONM (v); return (v); case tc_lisp_array: if (k >= a->storage_as.lisp_array.dim) err1_aset1 (i); a->storage_as.lisp_array.data[k] = v; return (v); default: return (my_err ("invalid argument to aset", a)); } } LISP arcons (long typecode, long n, long initp) { LISP a; long flag, j; flag = no_interrupt (1); a = cons (NIL, NIL); switch (typecode) { case tc_double_array: a->storage_as.double_array.dim = n; a->storage_as.double_array.data = (double *) must_malloc (n * sizeof (double)); if (initp) for (j = 0; j < n; ++j) a->storage_as.double_array.data[j] = 0.0; break; case tc_long_array: a->storage_as.long_array.dim = n; a->storage_as.long_array.data = (long *) must_malloc (n * sizeof (long)); if (initp) for (j = 0; j < n; ++j) a->storage_as.long_array.data[j] = 0; break; case tc_string: a->storage_as.string.dim = n; a->storage_as.string.data = (char *) must_malloc (n + 1); a->storage_as.string.data[n] = 0; if (initp) for (j = 0; j < n; ++j) a->storage_as.string.data[j] = ' '; case tc_byte_array: a->storage_as.string.dim = n; a->storage_as.string.data = (char *) must_malloc (n); if (initp) for (j = 0; j < n; ++j) a->storage_as.string.data[j] = 0; break; case tc_lisp_array: a->storage_as.lisp_array.dim = n; a->storage_as.lisp_array.data = (LISP *) must_malloc (n * sizeof (LISP)); for (j = 0; j < n; ++j) a->storage_as.lisp_array.data[j] = NIL; break; default: errswitch (); } a->type = typecode; no_interrupt (flag); return (a); } LISP mallocl (void *place, long size) { long n, r; LISP retval; n = size / sizeof (long); r = size % sizeof (long); if (r) ++n; retval = arcons (tc_long_array, n, 0); *(long **) place = retval->storage_as.long_array.data; return (retval); } LISP cons_array (LISP dim, LISP kind) { LISP a; long flag, n, j; if (NFLONUMP (dim) || (FLONM (dim) < 0)) return (my_err ("bad dimension to cons-array", dim)); else n = (long) FLONM (dim); flag = no_interrupt (1); a = cons (NIL, NIL); if EQ (cintern ("double"), kind) { a->type = tc_double_array; a->storage_as.double_array.dim = n; a->storage_as.double_array.data = (double *) must_malloc (n * sizeof (double)); for (j = 0; j < n; ++j) a->storage_as.double_array.data[j] = 0.0; } else if EQ (cintern ("long"), kind) { a->type = tc_long_array; a->storage_as.long_array.dim = n; a->storage_as.long_array.data = (long *) must_malloc (n * sizeof (long)); for (j = 0; j < n; ++j) a->storage_as.long_array.data[j] = 0; } else if EQ (cintern ("string"), kind) { a->type = tc_string; a->storage_as.string.dim = n; a->storage_as.string.data = (char *) must_malloc (n + 1); a->storage_as.string.data[n] = 0; for (j = 0; j < n; ++j) a->storage_as.string.data[j] = ' '; } else if EQ (cintern ("byte"), kind) { a->type = tc_byte_array; a->storage_as.string.dim = n; a->storage_as.string.data = (char *) must_malloc (n); for (j = 0; j < n; ++j) a->storage_as.string.data[j] = 0; } else if (EQ (cintern ("lisp"), kind) || NULLP (kind)) { a->type = tc_lisp_array; a->storage_as.lisp_array.dim = n; a->storage_as.lisp_array.data = (LISP *) must_malloc (n * sizeof (LISP)); for (j = 0; j < n; ++j) a->storage_as.lisp_array.data[j] = NIL; } else my_err ("bad type of array", kind); no_interrupt (flag); return (a); } LISP string_append (LISP args) { long size; LISP l, s; char *data; size = 0; for (l = args; NNULLP (l); l = cdr (l)) size += strlen (get_c_string (car (l))); s = strcons (size, NULL); data = s->storage_as.string.data; data[0] = 0; for (l = args; NNULLP (l); l = cdr (l)) strcat (data, get_c_string (car (l))); return (s); } LISP bytes_append (LISP args) { long size, n, j; LISP l, s; char *data, *ptr; size = 0; for (l = args; NNULLP (l); l = cdr (l)) { get_c_string_dim (car (l), &n); size += n; } s = arcons (tc_byte_array, size, 0); data = s->storage_as.string.data; for (j = 0, l = args; NNULLP (l); l = cdr (l)) { ptr = get_c_string_dim (car (l), &n); memcpy (&data[j], ptr, n); j += n; } return (s); } LISP substring (LISP str, LISP start, LISP end) { long s, e, n; char *data; data = get_c_string_dim (str, &n); s = get_c_long (start); if NULLP (end) e = n; else e = get_c_long (end); if ((s < 0) || (s > e)) my_err ("bad start index", start); if ((e < 0) || (e > n)) my_err ("bad end index", end); return (strcons (e - s, &data[s])); } LISP string_search (LISP token, LISP str) { char *s1, *s2, *ptr; s1 = get_c_string (str); s2 = get_c_string (token); ptr = strstr (s1, s2); if (ptr) return (flocons (ptr - s1)); else return (NIL); } #define IS_TRIM_SPACE(_x) (strchr(" \t\r\n",(_x))) LISP string_trim (LISP str) { char *start, *end; /*, *sp = " \t\r\n";*/ start = get_c_string (str); while (*start && IS_TRIM_SPACE (*start)) ++start; end = &start[strlen (start)]; while ((end > start) && IS_TRIM_SPACE (*(end - 1))) --end; return (strcons (end - start, start)); } LISP string_trim_left (LISP str) { char *start, *end; start = get_c_string (str); while (*start && IS_TRIM_SPACE (*start)) ++start; end = &start[strlen (start)]; return (strcons (end - start, start)); } LISP string_trim_right (LISP str) { char *start, *end; start = get_c_string (str); end = &start[strlen (start)]; while ((end > start) && IS_TRIM_SPACE (*(end - 1))) --end; return (strcons (end - start, start)); } LISP string_upcase (LISP str) { LISP result; char *s1, *s2; long j, n; s1 = get_c_string (str); n = strlen (s1); result = strcons (n, s1); s2 = get_c_string (result); for (j = 0; j < n; ++j) s2[j] = toupper (s2[j]); return (result); } LISP string_downcase (LISP str) { LISP result; char *s1, *s2; long j, n; s1 = get_c_string (str); n = strlen (s1); result = strcons (n, s1); s2 = get_c_string (result); for (j = 0; j < n; ++j) s2[j] = tolower (s2[j]); return (result); } LISP lreadstring (struct gen_readio * f) { int j, c, n; char *p; j = 0; p = tkbuffer; while (((c = GETC_FCN (f)) != '"') && (c != EOF)) { if (c == '\\') { c = GETC_FCN (f); if (c == EOF) my_err ("eof after \\", NIL); switch (c) { case '\\': c = '\\'; break; case 'n': c = '\n'; break; case 't': c = '\t'; break; case 'r': c = '\r'; break; case 'd': c = 0x04; break; case 'N': c = 0; break; case 's': c = ' '; break; case '0': n = 0; while (1) { c = GETC_FCN (f); if (c == EOF) my_err ("eof after \\0", NIL); if (isdigit (c)) n = n * 8 + c - '0'; else { UNGETC_FCN (c, f); break; } } c = n; } } if ((j + 1) >= TKBUFFERN) my_err ("read string overflow", NIL); ++j; *p++ = c; } *p = 0; return (strcons (j, tkbuffer)); } LISP lreadsharp (struct gen_readio * f) { LISP obj, l, result; long j, n; int c; c = GETC_FCN (f); switch (c) { case '(': UNGETC_FCN (c, f); obj = lreadr (f); n = nlength (obj); result = arcons (tc_lisp_array, n, 1); for (l = obj, j = 0; j < n; l = cdr (l), ++j) result->storage_as.lisp_array.data[j] = car (l); return (result); case '.': obj = lreadr (f); return (leval (obj, NIL)); case 'f': return (NIL); case 't': return (flocons (1)); default: return (my_err ("readsharp syntax not handled", NIL)); } } #define HASH_COMBINE(_h1,_h2,_mod) ((((_h1) * 17 + 1) ^ (_h2)) % (_mod)) long c_sxhash (LISP obj, long n) { long hash; unsigned char *s; LISP tmp; struct user_type_hooks *p; STACK_CHECK (&obj); INTERRUPT_CHECK (); switch TYPE (obj) { case tc_nil: return (0); case tc_cons: hash = c_sxhash (CAR (obj), n); for (tmp = CDR (obj); CONSP (tmp); tmp = CDR (tmp)) hash = HASH_COMBINE (hash, c_sxhash (CAR (tmp), n), n); hash = HASH_COMBINE (hash, c_sxhash (tmp, n), n); return (hash); case tc_symbol: for (hash = 0, s = (unsigned char *) PNAME (obj); *s; ++s) hash = HASH_COMBINE (hash, *s, n); return (hash); case tc_subr_0: case tc_subr_1: case tc_subr_2: case tc_subr_3: case tc_subr_4: case tc_subr_5: case tc_lsubr: case tc_fsubr: case tc_msubr: for (hash = 0, s = (unsigned char *) obj->storage_as.subr.name; *s; ++s) hash = HASH_COMBINE (hash, *s, n); return (hash); case tc_flonum: return (((unsigned long) FLONM (obj)) % n); default: p = get_user_type_hooks (TYPE (obj)); if (p->c_sxhash) return ((*p->c_sxhash) (obj, n)); else return (0); } } LISP sxhash (LISP obj, LISP n) { return (flocons (c_sxhash (obj, FLONUMP (n) ? (long) FLONM (n) : 10000))); } LISP equal (LISP a, LISP b) { struct user_type_hooks *p; long atype; STACK_CHECK (&a); loop: INTERRUPT_CHECK (); if EQ (a, b) return (sym_t); atype = TYPE (a); if (atype != TYPE (b)) return (NIL); switch (atype) { case tc_cons: if NULLP (equal (car (a), car (b))) return (NIL); a = cdr (a); b = cdr (b); goto loop; case tc_flonum: return ((FLONM (a) == FLONM (b)) ? sym_t : NIL); case tc_symbol: return (NIL); default: p = get_user_type_hooks (atype); if (p->equal) return ((*p->equal) (a, b)); else return (NIL); } } LISP array_equal (LISP a, LISP b) { long j, len; switch (TYPE (a)) { case tc_string: case tc_byte_array: len = a->storage_as.string.dim; if (len != b->storage_as.string.dim) return (NIL); if (memcmp (a->storage_as.string.data, b->storage_as.string.data, len) == 0) return (sym_t); else return (NIL); case tc_long_array: len = a->storage_as.long_array.dim; if (len != b->storage_as.long_array.dim) return (NIL); if (memcmp (a->storage_as.long_array.data, b->storage_as.long_array.data, len * sizeof (long)) == 0) return (sym_t); else return (NIL); case tc_double_array: len = a->storage_as.double_array.dim; if (len != b->storage_as.double_array.dim) return (NIL); for (j = 0; j < len; ++j) if (a->storage_as.double_array.data[j] != b->storage_as.double_array.data[j]) return (NIL); return (sym_t); case tc_lisp_array: len = a->storage_as.lisp_array.dim; if (len != b->storage_as.lisp_array.dim) return (NIL); for (j = 0; j < len; ++j) if NULLP (equal (a->storage_as.lisp_array.data[j], b->storage_as.lisp_array.data[j])) return (NIL); return (sym_t); default: return (errswitch ()); } } long array_sxhash (LISP a, long n) { long j, len, hash; unsigned char *char_data; unsigned long *long_data; double *double_data; switch (TYPE (a)) { case tc_string: case tc_byte_array: len = a->storage_as.string.dim; for (j = 0, hash = 0, char_data = (unsigned char *) a->storage_as.string.data; j < len; ++j, ++char_data) hash = HASH_COMBINE (hash, *char_data, n); return (hash); case tc_long_array: len = a->storage_as.long_array.dim; for (j = 0, hash = 0, long_data = (unsigned long *) a->storage_as.long_array.data; j < len; ++j, ++long_data) hash = HASH_COMBINE (hash, *long_data % n, n); return (hash); case tc_double_array: len = a->storage_as.double_array.dim; for (j = 0, hash = 0, double_data = a->storage_as.double_array.data; j < len; ++j, ++double_data) hash = HASH_COMBINE (hash, (unsigned long) *double_data % n, n); return (hash); case tc_lisp_array: len = a->storage_as.lisp_array.dim; for (j = 0, hash = 0; j < len; ++j) hash = HASH_COMBINE (hash, c_sxhash (a->storage_as.lisp_array.data[j], n), n); return (hash); default: errswitch (); return (0); } } long href_index (LISP table, LISP key) { long index; if NTYPEP (table, tc_lisp_array) my_err ("not a hash table", table); index = c_sxhash (key, table->storage_as.lisp_array.dim); if ((index < 0) || (index >= table->storage_as.lisp_array.dim)) { my_err ("sxhash inconsistency", table); return (0); } else return (index); } LISP href (LISP table, LISP key) { return (cdr (assoc (key, table->storage_as.lisp_array.data[href_index (table, key)]))); } LISP hset (LISP table, LISP key, LISP value) { long index; LISP cell, l; index = href_index (table, key); l = table->storage_as.lisp_array.data[index]; if NNULLP (cell = assoc (key, l)) return (setcdr (cell, value)); cell = cons (key, value); table->storage_as.lisp_array.data[index] = cons (cell, l); return (value); } LISP assoc (LISP x, LISP alist) { LISP l, tmp; for (l = alist; CONSP (l); l = CDR (l)) { tmp = CAR (l); if (CONSP (tmp) && equal (CAR (tmp), x)) return (tmp); INTERRUPT_CHECK (); } if EQ (l, NIL) return (NIL); return (my_err ("improper list to assoc", alist)); } LISP assv (LISP x, LISP alist) { LISP l, tmp; for (l = alist; CONSP (l); l = CDR (l)) { tmp = CAR (l); if (CONSP (tmp) && NNULLP (eql (CAR (tmp), x))) return (tmp); INTERRUPT_CHECK (); } if EQ (l, NIL) return (NIL); return (my_err ("improper list to assv", alist)); } void put_long (long i, FILE * f) { fwrite (&i, sizeof (long), 1, f); } long get_long (FILE * f) { long i; fread (&i, sizeof (long), 1, f); return (i); } long fast_print_table (LISP obj, LISP table) { FILE *f; LISP ht, index; f = get_c_file (car (table), (FILE *) NULL); if NULLP (ht = car (cdr (table))) return (1); index = href (ht, obj); if NNULLP (index) { putc (FO_fetch, f); put_long (get_c_long (index), f); return (0); } if NULLP (index = car (cdr (cdr (table)))) return (1); hset (ht, obj, index); FLONM (bashnum) = 1.0; setcar (cdr (cdr (table)), plus (index, bashnum)); putc (FO_store, f); put_long (get_c_long (index), f); return (1); } LISP fast_print (LISP obj, LISP table) { FILE *f; long len; LISP tmp; struct user_type_hooks *p; STACK_CHECK (&obj); f = get_c_file (car (table), (FILE *) NULL); switch (TYPE (obj)) { case tc_nil: putc (tc_nil, f); return (NIL); case tc_cons: for (len = 0, tmp = obj; CONSP (tmp); tmp = CDR (tmp)) { INTERRUPT_CHECK (); ++len; } if (len == 1) { putc (tc_cons, f); fast_print (car (obj), table); fast_print (cdr (obj), table); } else if NULLP (tmp) { putc (FO_list, f); put_long (len, f); for (tmp = obj; CONSP (tmp); tmp = CDR (tmp)) fast_print (CAR (tmp), table); } else { putc (FO_listd, f); put_long (len, f); for (tmp = obj; CONSP (tmp); tmp = CDR (tmp)) fast_print (CAR (tmp), table); fast_print (tmp, table); } return (NIL); case tc_flonum: putc (tc_flonum, f); fwrite (&obj->storage_as.flonum.data, sizeof (obj->storage_as.flonum.data), 1, f); return (NIL); case tc_symbol: if (fast_print_table (obj, table)) { putc (tc_symbol, f); len = strlen (PNAME (obj)); if (len >= TKBUFFERN) my_err ("symbol name too long", obj); put_long (len, f); fwrite (PNAME (obj), len, 1, f); return (sym_t); } else return (NIL); default: p = get_user_type_hooks (TYPE (obj)); if (p->fast_print) return ((*p->fast_print) (obj, table)); else return (my_err ("cannot fast-print", obj)); } } LISP fast_read (LISP table) { FILE *f; LISP tmp, l; struct user_type_hooks *p; int c; long len; f = get_c_file (car (table), (FILE *) NULL); c = getc (f); if (c == EOF) return (table); switch (c) { case FO_comment: while ((c = getc (f))) switch (c) { case EOF: return (table); case '\n': return (fast_read (table)); } case FO_fetch: len = get_long (f); FLONM (bashnum) = len; return (href (car (cdr (table)), bashnum)); case FO_store: len = get_long (f); tmp = fast_read (table); hset (car (cdr (table)), flocons (len), tmp); return (tmp); case tc_nil: return (NIL); case tc_cons: tmp = fast_read (table); return (cons (tmp, fast_read (table))); case FO_list: case FO_listd: len = get_long (f); FLONM (bashnum) = len; l = make_list (bashnum, NIL); tmp = l; while (len > 1) { CAR (tmp) = fast_read (table); tmp = CDR (tmp); --len; } CAR (tmp) = fast_read (table); if (c == FO_listd) CDR (tmp) = fast_read (table); return (l); case tc_flonum: tmp = newcell (tc_flonum); fread (&tmp->storage_as.flonum.data, sizeof (tmp->storage_as.flonum.data), 1, f); return (tmp); case tc_symbol: len = get_long (f); if (len >= TKBUFFERN) my_err ("symbol name too long", NIL); fread (tkbuffer, len, 1, f); tkbuffer[len] = 0; return (rintern (tkbuffer)); default: p = get_user_type_hooks (c); if (p->fast_read) return (*p->fast_read) (c, table); else return (my_err ("unknown fast-read opcode", flocons (c))); } } LISP array_fast_print (LISP ptr, LISP table) { int j, len; FILE *f; f = get_c_file (car (table), (FILE *) NULL); switch (ptr->type) { case tc_string: case tc_byte_array: putc (ptr->type, f); len = ptr->storage_as.string.dim; put_long (len, f); fwrite (ptr->storage_as.string.data, len, 1, f); return (NIL); case tc_double_array: putc (tc_double_array, f); len = ptr->storage_as.double_array.dim * sizeof (double); put_long (len, f); fwrite (ptr->storage_as.double_array.data, len, 1, f); return (NIL); case tc_long_array: putc (tc_long_array, f); len = ptr->storage_as.long_array.dim * sizeof (long); put_long (len, f); fwrite (ptr->storage_as.long_array.data, len, 1, f); return (NIL); case tc_lisp_array: putc (tc_lisp_array, f); len = ptr->storage_as.lisp_array.dim; put_long (len, f); for (j = 0; j < len; ++j) fast_print (ptr->storage_as.lisp_array.data[j], table); return (NIL); default: return (errswitch ()); } } LISP array_fast_read (int code, LISP table) { long j, len, iflag; FILE *f; LISP ptr; f = get_c_file (car (table), (FILE *) NULL); switch (code) { case tc_string: len = get_long (f); ptr = strcons (len, NULL); fread (ptr->storage_as.string.data, len, 1, f); ptr->storage_as.string.data[len] = 0; return (ptr); case tc_byte_array: len = get_long (f); iflag = no_interrupt (1); ptr = newcell (tc_byte_array); ptr->storage_as.string.dim = len; ptr->storage_as.string.data = (char *) must_malloc (len); fread (ptr->storage_as.string.data, len, 1, f); no_interrupt (iflag); return (ptr); case tc_double_array: len = get_long (f); iflag = no_interrupt (1); ptr = newcell (tc_double_array); ptr->storage_as.double_array.dim = len; ptr->storage_as.double_array.data = (double *) must_malloc (len * sizeof (double)); fread (ptr->storage_as.double_array.data, sizeof (double), len, f); no_interrupt (iflag); return (ptr); case tc_long_array: len = get_long (f); iflag = no_interrupt (1); ptr = newcell (tc_long_array); ptr->storage_as.long_array.dim = len; ptr->storage_as.long_array.data = (long *) must_malloc (len * sizeof (long)); fread (ptr->storage_as.long_array.data, sizeof (long), len, f); no_interrupt (iflag); return (ptr); case tc_lisp_array: len = get_long (f); FLONM (bashnum) = len; ptr = cons_array (bashnum, NIL); for (j = 0; j < len; ++j) ptr->storage_as.lisp_array.data[j] = fast_read (table); return (ptr); default: return (errswitch ()); } } long get_c_long (LISP x) { if NFLONUMP (x) my_err ("not a number", x); return ((long) FLONM (x)); } double get_c_double (LISP x) { if NFLONUMP (x) my_err ("not a number", x); return (FLONM (x)); } LISP make_list (LISP x, LISP v) { long n; LISP l; n = get_c_long (x); l = NIL; while (n > 0) { l = cons (v, l); --n; } return (l); } LISP lfread (LISP size, LISP file) { long flag, n, ret, m; char *buffer; LISP s; FILE *f; f = get_c_file (file, stdin); flag = no_interrupt (1); switch (TYPE (size)) { case tc_string: case tc_byte_array: s = size; buffer = s->storage_as.string.data; n = s->storage_as.string.dim; m = 0; break; default: n = get_c_long (size); buffer = (char *) must_malloc (n + 1); buffer[n] = 0; m = 1; } ret = fread (buffer, 1, n, f); if (ret == 0) { if (m) free (buffer); no_interrupt (flag); return (NIL); } if (m) { if (ret == n) { s = cons (NIL, NIL); s->type = tc_string; s->storage_as.string.data = buffer; s->storage_as.string.dim = n; } else { s = strcons (ret, NULL); memcpy (s->storage_as.string.data, buffer, ret); free (buffer); } no_interrupt (flag); return (s); } no_interrupt (flag); return (flocons ((double) ret)); } LISP lfwrite (LISP string, LISP file) { FILE *f; long flag; char *data; long dim, len; f = get_c_file (file, stdout); data = get_c_string_dim (CONSP (string) ? car (string) : string, &dim); len = CONSP (string) ? get_c_long (cadr (string)) : dim; if (len <= 0) return (NIL); if (len > dim) my_err ("write length too long", string); flag = no_interrupt (1); fwrite (data, 1, len, f); no_interrupt (flag); return (NIL); } LISP lfflush (LISP file) { FILE *f; long flag; f = get_c_file (file, stdout); flag = no_interrupt (1); fflush (f); no_interrupt (flag); return (NIL); } LISP string_length (LISP string) { if NTYPEP (string, tc_string) err_wta_str (string); return (flocons (strlen (string->storage_as.string.data))); } LISP string_dim (LISP string) { if NTYPEP (string, tc_string) err_wta_str (string); return (flocons ((double) string->storage_as.string.dim)); } long nlength (LISP obj) { LISP l; long n; switch TYPE (obj) { case tc_string: return (strlen (obj->storage_as.string.data)); case tc_byte_array: return (obj->storage_as.string.dim); case tc_double_array: return (obj->storage_as.double_array.dim); case tc_long_array: return (obj->storage_as.long_array.dim); case tc_lisp_array: return (obj->storage_as.lisp_array.dim); case tc_nil: return (0); case tc_cons: for (l = obj, n = 0; CONSP (l); l = CDR (l), ++n) INTERRUPT_CHECK (); if NNULLP (l) my_err ("improper list to length", obj); return (n); default: my_err ("wta to length", obj); return (0); } } LISP llength (LISP obj) { return (flocons (nlength (obj))); } LISP number2string (LISP x, LISP b, LISP w, LISP p) { char buffer[1000]; double y; long base, width, prec; if NFLONUMP (x) my_err ("wta", x); y = FLONM (x); width = NNULLP (w) ? get_c_long (w) : -1; if (width > 100) my_err ("width too long", w); prec = NNULLP (p) ? get_c_long (p) : -1; if (prec > 100) my_err ("precision too large", p); if (NULLP (b) || EQ (sym_e, b) || EQ (sym_f, b)) { if ((width >= 0) && (prec >= 0)) sprintf (buffer, NULLP (b) ? "% *.*g" : EQ (sym_e, b) ? "% *.*e" : "% *.*f", width, prec, y); else if (width >= 0) sprintf (buffer, NULLP (b) ? "% *g" : EQ (sym_e, b) ? "% *e" : "% *f", width, y); else if (prec >= 0) sprintf (buffer, NULLP (b) ? "%.*g" : EQ (sym_e, b) ? "%.*e" : "%.*f", prec, y); else sprintf (buffer, NULLP (b) ? "%g" : EQ (sym_e, b) ? "%e" : "%f", y); } else if (((base = get_c_long (b)) == 10) || (base == 8) || (base == 16)) { if (width >= 0) sprintf (buffer, (base == 10) ? "%0*ld" : (base == 8) ? "%0*lo" : "%0*lX", width, (long) y); else sprintf (buffer, (base == 10) ? "%ld" : (base == 8) ? "%lo" : "%lX", (long) y); } else my_err ("number base not handled", b); return (strcons (strlen (buffer), buffer)); } LISP string2number (LISP x, LISP b) { char *str; long base, value = 0; double result = 0.0; str = get_c_string (x); if NULLP (b) result = atof (str); else if ((base = get_c_long (b)) == 10) { sscanf (str, "%ld", &value); result = (double) value; } else if (base == 8) { sscanf (str, "%lo", &value); result = (double) value; } else if (base == 16) { sscanf (str, "%lx", &value); result = (double) value; } else if ((base >= 1) && (base <= 16)) { for (result = 0.0; *str; ++str) if (isdigit (*str)) result = result * base + *str - '0'; else if (isxdigit (*str)) result = result * base + toupper (*str) - 'A' + 10; } else my_err ("number base not handled", b); return (flocons (result)); } LISP lstrcmp (LISP s1, LISP s2) { return (flocons (strcmp (get_c_string (s1), get_c_string (s2)))); } void chk_string (LISP s, char **data, long *dim) { if TYPEP (s, tc_string) { *data = s->storage_as.string.data; *dim = s->storage_as.string.dim; } else err_wta_str (s); } LISP lstrcpy (LISP dest, LISP src) { long ddim, slen; char *d, *s; chk_string (dest, &d, &ddim); s = get_c_string (src); slen = strlen (s); if (slen > ddim) my_err ("string too long", src); memcpy (d, s, slen); d[slen] = 0; return (NIL); } LISP lstrcat (LISP dest, LISP src) { long ddim, dlen, slen; char *d, *s; chk_string (dest, &d, &ddim); s = get_c_string (src); slen = strlen (s); dlen = strlen (d); if ((slen + dlen) > ddim) my_err ("string too long", src); memcpy (&d[dlen], s, slen); d[dlen + slen] = 0; return (NIL); } LISP lstrbreakup (LISP str, LISP lmarker) { char *start, *end, *marker; size_t k; LISP result = NIL; start = get_c_string (str); marker = get_c_string (lmarker); k = strlen (marker); while (*start) { if (!(end = strstr (start, marker))) end = &start[strlen (start)]; result = cons (strcons (end - start, start), result); start = (*end) ? end + k : end; } return (nreverse (result)); } LISP lstrunbreakup (LISP elems, LISP lmarker) { LISP result, l; for (l = elems, result = NIL; NNULLP (l); l = cdr (l)) if EQ (l, elems) result = cons (car (l), result); else result = cons (car (l), cons (lmarker, result)); return (string_append (nreverse (result))); } LISP stringp (LISP x) { return (TYPEP (x, tc_string) ? sym_t : NIL); } static char *base64_encode_table = "\ ABCDEFGHIJKLMNOPQRSTUVWXYZ\ abcdefghijklmnopqrstuvwxyz\ 0123456789+/="; static char *base64_decode_table = NULL; static void init_base64_table (void) { int j; base64_decode_table = (char *) malloc (256); memset (base64_decode_table, -1, 256); for (j = 0; j < 65; ++j) base64_decode_table[(unsigned char) base64_encode_table[j]] = j; } #define BITMSK(N) ((1 << (N)) - 1) #define ITEM1(X) (X >> 2) & BITMSK(6) #define ITEM2(X,Y) ((X & BITMSK(2)) << 4) | ((Y >> 4) & BITMSK(4)) #define ITEM3(X,Y) ((X & BITMSK(4)) << 2) | ((Y >> 6) & BITMSK(2)) #define ITEM4(X) X & BITMSK(6) LISP base64encode (LISP in) { char *s, *t = base64_encode_table; unsigned char *p1, *p2; LISP out; long j, m, n, chunks, leftover; s = get_c_string_dim (in, &n); chunks = n / 3; leftover = n % 3; m = (chunks + ((leftover) ? 1 : 0)) * 4; out = strcons (m, NULL); p2 = (unsigned char *) get_c_string (out); for (j = 0, p1 = (unsigned char *) s; j < chunks; ++j, p1 += 3) { *p2++ = t[ITEM1 (p1[0])]; *p2++ = t[ITEM2 (p1[0], p1[1])]; *p2++ = t[ITEM3 (p1[1], p1[2])]; *p2++ = t[ITEM4 (p1[2])]; } switch (leftover) { case 0: break; case 1: *p2++ = t[ITEM1 (p1[0])]; *p2++ = t[ITEM2 (p1[0], 0)]; *p2++ = base64_encode_table[64]; *p2++ = base64_encode_table[64]; break; case 2: *p2++ = t[ITEM1 (p1[0])]; *p2++ = t[ITEM2 (p1[0], p1[1])]; *p2++ = t[ITEM3 (p1[1], 0)]; *p2++ = base64_encode_table[64]; break; default: errswitch (); } return (out); } LISP base64decode (LISP in) { char *s, *t = base64_decode_table; LISP out; unsigned char *p1, *p2; long j, m, n, chunks, leftover, item1, item2, item3, item4; s = get_c_string (in); n = strlen (s); if (n == 0) return (strcons (0, NULL)); if (n % 4) my_err ("illegal base64 data length", in); if (s[n - 1] == base64_encode_table[64]) { if (s[n - 2] == base64_encode_table[64]) leftover = 1; else leftover = 2; } else leftover = 0; chunks = (n / 4) - ((leftover) ? 1 : 0); m = (chunks * 3) + leftover; out = strcons (m, NULL); p2 = (unsigned char *) get_c_string (out); for (j = 0, p1 = (unsigned char *) s; j < chunks; ++j, p1 += 4) { if ((item1 = t[p1[0]]) & ~BITMSK (6)) return (NIL); if ((item2 = t[p1[1]]) & ~BITMSK (6)) return (NIL); if ((item3 = t[p1[2]]) & ~BITMSK (6)) return (NIL); if ((item4 = t[p1[3]]) & ~BITMSK (6)) return (NIL); *p2++ = (item1 << 2) | (item2 >> 4); *p2++ = (item2 << 4) | (item3 >> 2); *p2++ = (item3 << 6) | item4; } switch (leftover) { case 0: break; case 1: if ((item1 = t[p1[0]]) & ~BITMSK (6)) return (NIL); if ((item2 = t[p1[1]]) & ~BITMSK (6)) return (NIL); *p2++ = (item1 << 2) | (item2 >> 4); break; case 2: if ((item1 = t[p1[0]]) & ~BITMSK (6)) return (NIL); if ((item2 = t[p1[1]]) & ~BITMSK (6)) return (NIL); if ((item3 = t[p1[2]]) & ~BITMSK (6)) return (NIL); *p2++ = (item1 << 2) | (item2 >> 4); *p2++ = (item2 << 4) | (item3 >> 2); break; default: errswitch (); } return (out); } LISP memq (LISP x, LISP il) { LISP l, tmp; for (l = il; CONSP (l); l = CDR (l)) { tmp = CAR (l); if EQ (x, tmp) return (l); INTERRUPT_CHECK (); } if EQ (l, NIL) return (NIL); return (my_err ("improper list to memq", il)); } LISP member (LISP x, LISP il) { LISP l, tmp; for (l = il; CONSP (l); l = CDR (l)) { tmp = CAR (l); if NNULLP (equal (x, tmp)) return (l); INTERRUPT_CHECK (); } if EQ (l, NIL) return (NIL); return (my_err ("improper list to member", il)); } LISP memv (LISP x, LISP il) { LISP l, tmp; for (l = il; CONSP (l); l = CDR (l)) { tmp = CAR (l); if NNULLP (eql (x, tmp)) return (l); INTERRUPT_CHECK (); } if EQ (l, NIL) return (NIL); return (my_err ("improper list to memv", il)); } LISP nth (LISP x, LISP li) { LISP l; long j, n = get_c_long (x); for (j = 0, l = li; (j < n) && CONSP (l); ++j) l = CDR (l); if CONSP (l) return (CAR (l)); else return (my_err ("bad arg to nth", x)); } /* these lxxx_default functions are convenient for manipulating command-line argument lists */ LISP lref_default (LISP li, LISP x, LISP fcn) { LISP l; long j, n = get_c_long (x); for (j = 0, l = li; (j < n) && CONSP (l); ++j) l = CDR (l); if CONSP (l) return (CAR (l)); else if NNULLP (fcn) return (lapply (fcn, NIL)); else return (NIL); } LISP larg_default (LISP li, LISP x, LISP dval) { LISP l = li, elem; long j = 0, n = get_c_long (x); while NNULLP (l) { elem = car (l); if (TYPEP (elem, tc_string) && strchr ("-:", *get_c_string (elem))) l = cdr (l); else if (j == n) return (elem); else { l = cdr (l); ++j; } } return (dval); } LISP lkey_default (LISP li, LISP key, LISP dval) { LISP l = li, elem; char *ckey, *celem; long n; ckey = get_c_string (key); n = strlen (ckey); while NNULLP (l) { elem = car (l); if (TYPEP (elem, tc_string) && (*(celem = get_c_string (elem)) == ':') && (strncmp (&celem[1], ckey, n) == 0) && (celem[n + 1] == '=')) return (strcons (strlen (&celem[n + 2]), &celem[n + 2])); l = cdr (l); } return (dval); } LISP llist (LISP l) { return (l); } LISP writes1 (FILE * f, LISP l) { LISP v; STACK_CHECK (&v); INTERRUPT_CHECK (); for (v = l; CONSP (v); v = CDR (v)) writes1 (f, CAR (v)); switch TYPE (v) { case tc_nil: break; case tc_symbol: case tc_string: fput_st (f, get_c_string (v)); break; default: lprin1f (v, f); break; } return (NIL); } LISP writes (LISP args) { return (writes1 (get_c_file (car (args), stdout), cdr (args))); } LISP last (LISP l) { LISP v1, v2; v1 = l; v2 = CONSP (v1) ? CDR (v1) : my_err ("bad arg to last", l); while (CONSP (v2)) { INTERRUPT_CHECK (); v1 = v2; v2 = CDR (v2); } return (v1); } LISP butlast (LISP l) { INTERRUPT_CHECK (); STACK_CHECK (&l); if NULLP (l) my_err ("list is empty", l); if CONSP (l) { if NULLP (CDR (l)) return (NIL); else return (cons (CAR (l), butlast (CDR (l)))); } return (my_err ("not a list", l)); } LISP nconc (LISP a, LISP b) { if NULLP (a) return (b); setcdr (last (a), b); return (a); } LISP funcall1 (LISP fcn, LISP a1) { switch TYPE (fcn) { case tc_subr_1: STACK_CHECK (&fcn); INTERRUPT_CHECK (); return (SUBR1 (fcn) (a1)); case tc_closure: if TYPEP (fcn->storage_as.closure.code, tc_subr_2) { STACK_CHECK (&fcn); INTERRUPT_CHECK (); return (SUBR2 (fcn->storage_as.closure.code) (fcn->storage_as.closure.env, a1)); } default: return (lapply (fcn, cons (a1, NIL))); } } LISP funcall2 (LISP fcn, LISP a1, LISP a2) { switch TYPE (fcn) { case tc_subr_2: case tc_subr_2n: STACK_CHECK (&fcn); INTERRUPT_CHECK (); return (SUBR2 (fcn) (a1, a2)); default: return (lapply (fcn, cons (a1, cons (a2, NIL)))); } } LISP lqsort (LISP l, LISP f, LISP g) /* this is a stupid recursive qsort */ { int j, n; LISP v, mark, less, notless; for (v = l, n = 0; CONSP (v); v = CDR (v), ++n) INTERRUPT_CHECK (); if NNULLP (v) my_err ("bad list to qsort", l); if (n == 0) return (NIL); j = rand () % n; for (v = l, n = 0; n < j; ++n) v = CDR (v); mark = CAR (v); for (less = NIL, notless = NIL, v = l, n = 0; NNULLP (v); v = CDR (v), ++n) if (j != n) { if NNULLP (funcall2 (f, NULLP (g) ? CAR (v) : funcall1 (g, CAR (v)), NULLP (g) ? mark : funcall1 (g, mark))) less = cons (CAR (v), less); else notless = cons (CAR (v), notless); } return (nconc (lqsort (less, f, g), cons (mark, lqsort (notless, f, g)))); } LISP string_lessp (LISP s1, LISP s2) { if (strcmp (get_c_string (s1), get_c_string (s2)) < 0) return (sym_t); else return (NIL); } LISP benchmark_funcall1 (LISP ln, LISP f, LISP a1) { long j, n; LISP value = NIL; n = get_c_long (ln); for (j = 0; j < n; ++j) value = funcall1 (f, a1); return (value); } LISP benchmark_funcall2 (LISP l) { long j, n; LISP ln = car (l); LISP f = car (cdr (l)); LISP a1 = car (cdr (cdr (l))); LISP a2 = car (cdr (cdr (cdr (l)))); LISP value = NULL; n = get_c_long (ln); for (j = 0; j < n; ++j) value = funcall2 (f, a1, a2); return (value); } LISP benchmark_eval (LISP ln, LISP exp, LISP env) { long j, n; LISP value = NIL; n = get_c_long (ln); for (j = 0; j < n; ++j) value = leval (exp, env); return (value); } LISP mapcar1 (LISP fcn, LISP in) { LISP res, ptr, l; if NULLP (in) return (NIL); res = ptr = cons (funcall1 (fcn, car (in)), NIL); for (l = cdr (in); CONSP (l); l = CDR (l)) ptr = CDR (ptr) = cons (funcall1 (fcn, CAR (l)), CDR (ptr)); return (res); } LISP mapcar2 (LISP fcn, LISP in1, LISP in2) { LISP res, ptr, l1, l2; if (NULLP (in1) || NULLP (in2)) return (NIL); res = ptr = cons (funcall2 (fcn, car (in1), car (in2)), NIL); for (l1 = cdr (in1), l2 = cdr (in2); CONSP (l1) && CONSP (l2); l1 = CDR (l1), l2 = CDR (l2)) ptr = CDR (ptr) = cons (funcall2 (fcn, CAR (l1), CAR (l2)), CDR (ptr)); return (res); } LISP mapcar (LISP l) { LISP fcn = car (l); switch (get_c_long (llength (l))) { case 2: return (mapcar1 (fcn, car (cdr (l)))); case 3: return (mapcar2 (fcn, car (cdr (l)), car (cdr (cdr (l))))); default: return (my_err ("mapcar case not handled", l)); } } LISP lfmod (LISP x, LISP y) { if NFLONUMP (x) my_err ("wta(1st) to fmod", x); if NFLONUMP (y) my_err ("wta(2nd) to fmod", y); return (flocons (fmod (FLONM (x), FLONM (y)))); } LISP lsubset (LISP fcn, LISP l) { LISP result = NIL, v; for (v = l; CONSP (v); v = CDR (v)) if NNULLP (funcall1 (fcn, CAR (v))) result = cons (CAR (v), result); return (nreverse (result)); } LISP ass (LISP x, LISP alist, LISP fcn) { LISP l, tmp; for (l = alist; CONSP (l); l = CDR (l)) { tmp = CAR (l); if (CONSP (tmp) && NNULLP (funcall2 (fcn, CAR (tmp), x))) return (tmp); INTERRUPT_CHECK (); } if EQ (l, NIL) return (NIL); return (my_err ("improper list to ass", alist)); } LISP append2 (LISP l1, LISP l2) { long n; LISP result = NIL, p1, p2; n = nlength (l1) + nlength (l2); while (n > 0) { result = cons (NIL, result); --n; } for (p1 = result, p2 = l1; NNULLP (p2); p1 = cdr (p1), p2 = cdr (p2)) setcar (p1, car (p2)); for (p2 = l2; NNULLP (p2); p1 = cdr (p1), p2 = cdr (p2)) setcar (p1, car (p2)); return (result); } LISP append (LISP l) { STACK_CHECK (&l); INTERRUPT_CHECK (); if NULLP (l) return (NIL); else if NULLP (cdr (l)) return (car (l)); else if NULLP (cddr (l)) return (append2 (car (l), cadr (l))); else return (append2 (car (l), append (cdr (l)))); } LISP listn (long n,...) { LISP result, ptr; long j; va_list args; for (j = 0, result = NIL; j < n; ++j) result = cons (NIL, result); va_start (args, n); for (j = 0, ptr = result; j < n; ptr = cdr (ptr), ++j) setcar (ptr, va_arg (args, LISP)); va_end (args); return (result); } LISP fast_load (LISP lfname, LISP noeval) { char *fname; LISP stream; LISP result = NIL, form; fname = get_c_string (lfname); if (siod_verbose_level >= 3) { put_st ("fast loading "); put_st (fname); put_st ("\n"); } stream = listn (3, fopen_c (fname, "rb"), cons_array (flocons (100), NIL), flocons (0)); while (NEQ (stream, form = fast_read (stream))) { if (siod_verbose_level >= 5) lprint (form, NIL); if NULLP (noeval) leval (form, NIL); else result = cons (form, result); } fclose_l (car (stream)); if (siod_verbose_level >= 3) put_st ("done.\n"); return (nreverse (result)); } static void shexstr (char *outstr, void *buff, size_t len) { unsigned char *data = buff; size_t j; for (j = 0; j < len; ++j) sprintf (&outstr[j * 2], "%02X", data[j]); } LISP fast_save (LISP fname, LISP forms, LISP nohash, LISP comment) { char *cname, msgbuff[100], databuff[50]; LISP stream, l; FILE *f; long l_one = 1; double d_one = 1.0; cname = get_c_string (fname); if (siod_verbose_level >= 3) { put_st ("fast saving forms to "); put_st (cname); put_st ("\n"); } stream = listn (3, fopen_c (cname, "wb"), NNULLP (nohash) ? NIL : cons_array (flocons (100), NIL), flocons (0)); f = get_c_file (car (stream), NULL); if NNULLP (comment) fput_st (f, get_c_string (comment)); sprintf (msgbuff, "# Siod Binary Object Save File\n"); fput_st (f, msgbuff); sprintf (msgbuff, "# sizeof(long) = %d\n# sizeof(double) = %d\n", sizeof (long), sizeof (double)); fput_st (f, msgbuff); shexstr (databuff, &l_one, sizeof (l_one)); sprintf (msgbuff, "# 1 = %s\n", databuff); fput_st (f, msgbuff); shexstr (databuff, &d_one, sizeof (d_one)); sprintf (msgbuff, "# 1.0 = %s\n", databuff); fput_st (f, msgbuff); for (l = forms; NNULLP (l); l = cdr (l)) fast_print (car (l), stream); fclose_l (car (stream)); if (siod_verbose_level >= 3) put_st ("done.\n"); return (NIL); } void swrite1 (LISP stream, LISP data) { FILE *f = get_c_file (stream, stdout); switch TYPE (data) { case tc_symbol: case tc_string: fput_st (f, get_c_string (data)); break; default: lprin1f (data, f); break; } } LISP swrite (LISP stream, LISP table, LISP data) { LISP value, key; long j, k, m, n; switch (TYPE (data)) { case tc_symbol: value = href (table, data); if CONSP (value) { swrite1 (stream, CAR (value)); if NNULLP (CDR (value)) hset (table, data, CDR (value)); } else swrite1 (stream, value); break; case tc_lisp_array: n = data->storage_as.lisp_array.dim; if (n < 1) my_err ("no object repeat count", data); key = data->storage_as.lisp_array.data[0]; if NULLP (value = href (table, key)) value = key; else if CONSP (value) { if NNULLP (CDR (value)) hset (table, key, CDR (value)); value = CAR (value); } m = get_c_long (value); for (k = 0; k < m; ++k) for (j = 1; j < n; ++j) swrite (stream, table, data->storage_as.lisp_array.data[j]); break; case tc_cons: /* this should be handled similar to the array case */ default: swrite1 (stream, data); } return (NIL); } LISP lpow (LISP x, LISP y) { if NFLONUMP (x) my_err ("wta(1st) to pow", x); if NFLONUMP (y) my_err ("wta(2nd) to pow", y); return (flocons (pow (FLONM (x), FLONM (y)))); } LISP lexp (LISP x) { return (flocons (exp (get_c_double (x)))); } LISP llog (LISP x) { return (flocons (log (get_c_double (x)))); } LISP lsin (LISP x) { return (flocons (sin (get_c_double (x)))); } LISP lcos (LISP x) { return (flocons (cos (get_c_double (x)))); } LISP ltan (LISP x) { return (flocons (tan (get_c_double (x)))); } LISP lasin (LISP x) { return (flocons (asin (get_c_double (x)))); } LISP lacos (LISP x) { return (flocons (acos (get_c_double (x)))); } LISP latan (LISP x) { return (flocons (atan (get_c_double (x)))); } LISP latan2 (LISP x, LISP y) { return (flocons (atan2 (get_c_double (x), get_c_double (y)))); } LISP hexstr (LISP a) { unsigned char *in; char *out; LISP result; long j, dim; in = (unsigned char *) get_c_string_dim (a, &dim); result = strcons (dim * 2, NULL); for (out = get_c_string (result), j = 0; j < dim; ++j, out += 2) sprintf (out, "%02x", in[j]); return (result); } static int xdigitvalue (int c) { if (isdigit (c)) return (c - '0'); if (isxdigit (c)) return (toupper (c) - 'A' + 10); return (0); } LISP hexstr2bytes (LISP a) { char *in; unsigned char *out; LISP result; long j, dim; in = get_c_string (a); dim = strlen (in) / 2; result = arcons (tc_byte_array, dim, 0); out = (unsigned char *) result->storage_as.string.data; for (j = 0; j < dim; ++j) out[j] = xdigitvalue (in[j * 2]) * 16 + xdigitvalue (in[j * 2 + 1]); return (result); } LISP getprop (LISP plist, LISP key) { LISP l; for (l = cdr (plist); NNULLP (l); l = cddr (l)) if EQ (car (l), key) return (cadr (l)); else INTERRUPT_CHECK (); return (NIL); } LISP setprop (LISP plist, LISP key, LISP value) { my_err ("not implemented", NIL); return (NIL); } LISP putprop (LISP plist, LISP value, LISP key) { return (setprop (plist, key, value)); } LISP ltypeof (LISP obj) { long x; x = TYPE (obj); switch (x) { case tc_nil: return (cintern ("tc_nil")); case tc_cons: return (cintern ("tc_cons")); case tc_flonum: return (cintern ("tc_flonum")); case tc_symbol: return (cintern ("tc_symbol")); case tc_subr_0: return (cintern ("tc_subr_0")); case tc_subr_1: return (cintern ("tc_subr_1")); case tc_subr_2: return (cintern ("tc_subr_2")); case tc_subr_2n: return (cintern ("tc_subr_2n")); case tc_subr_3: return (cintern ("tc_subr_3")); case tc_subr_4: return (cintern ("tc_subr_4")); case tc_subr_5: return (cintern ("tc_subr_5")); case tc_lsubr: return (cintern ("tc_lsubr")); case tc_fsubr: return (cintern ("tc_fsubr")); case tc_msubr: return (cintern ("tc_msubr")); case tc_closure: return (cintern ("tc_closure")); case tc_free_cell: return (cintern ("tc_free_cell")); case tc_string: return (cintern ("tc_string")); case tc_byte_array: return (cintern ("tc_byte_array")); case tc_double_array: return (cintern ("tc_double_array")); case tc_long_array: return (cintern ("tc_long_array")); case tc_lisp_array: return (cintern ("tc_lisp_array")); case tc_c_file: return (cintern ("tc_c_file")); default: return (flocons (x)); } } LISP caaar (LISP x) { return (car (car (car (x)))); } LISP caadr (LISP x) { return (car (car (cdr (x)))); } LISP cadar (LISP x) { return (car (cdr (car (x)))); } LISP caddr (LISP x) { return (car (cdr (cdr (x)))); } LISP cdaar (LISP x) { return (cdr (car (car (x)))); } LISP cdadr (LISP x) { return (cdr (car (cdr (x)))); } LISP cddar (LISP x) { return (cdr (cdr (car (x)))); } LISP cdddr (LISP x) { return (cdr (cdr (cdr (x)))); } LISP ash (LISP value, LISP n) { long m, k; m = get_c_long (value); k = get_c_long (n); if (k > 0) m = m << k; else m = m >> (-k); return (flocons (m)); } LISP bitand (LISP a, LISP b) { return (flocons (get_c_long (a) & get_c_long (b))); } LISP bitor (LISP a, LISP b) { return (flocons (get_c_long (a) | get_c_long (b))); } LISP bitxor (LISP a, LISP b) { return (flocons (get_c_long (a) ^ get_c_long (b))); } LISP bitnot (LISP a) { return (flocons (~get_c_long (a))); } LISP leval_prog1 (LISP args, LISP env) { LISP retval, l; retval = leval (car (args), env); for (l = cdr (args); NNULLP (l); l = cdr (l)) leval (car (l), env); return (retval); } LISP leval_cond (LISP * pform, LISP * penv) { LISP args, env, clause, value, next; args = cdr (*pform); env = *penv; if NULLP (args) { *pform = NIL; return (NIL); } next = cdr (args); while NNULLP (next) { clause = car (args); value = leval (car (clause), env); if NNULLP (value) { clause = cdr (clause); if NULLP (clause) { *pform = value; return (NIL); } else { next = cdr (clause); while (NNULLP (next)) { leval (car (clause), env); clause = next; next = cdr (next); } *pform = car (clause); return (sym_t); } } args = next; next = cdr (next); } clause = car (args); next = cdr (clause); if NULLP (next) { *pform = car (clause); return (sym_t); } value = leval (car (clause), env); if NULLP (value) { *pform = NIL; return (NIL); } clause = next; next = cdr (next); while (NNULLP (next)) { leval (car (clause), env); clause = next; next = cdr (next); } *pform = car (clause); return (sym_t); } LISP lstrspn (LISP str1, LISP str2) { return (flocons (strspn (get_c_string (str1), get_c_string (str2)))); } LISP lstrcspn (LISP str1, LISP str2) { return (flocons (strcspn (get_c_string (str1), get_c_string (str2)))); } LISP substring_equal (LISP str1, LISP str2, LISP start, LISP end) { char *cstr1, *cstr2; long len1, n, s, e; cstr1 = get_c_string_dim (str1, &len1); cstr2 = get_c_string_dim (str2, &n); s = NULLP (start) ? 0 : get_c_long (start); e = NULLP (end) ? n : get_c_long (end); if ((s < 0) || (s > e) || (e < 0) || (e > n) || ((e - s) != len1)) return (NIL); return ((memcmp (cstr1, &cstr2[s], e - s) == 0) ? a_true_value () : NIL); } LISP set_eval_history (LISP len, LISP circ) { LISP data; data = NULLP (len) ? len : make_list (len, NIL); if NNULLP (circ) data = nconc (data, data); setvar (cintern ("*eval-history-ptr*"), data, NIL); setvar (cintern ("*eval-history*"), data, NIL); return (len); } static LISP parser_fasl (LISP ignore) { return (closure (listn (3, NIL, cons_array (flocons (100), NIL), flocons (0)), leval (cintern ("parser_fasl_hook"), NIL))); } static LISP parser_fasl_hook (LISP env, LISP f) { LISP result; setcar (env, f); result = fast_read (env); if EQ (result, env) return (get_eof_val ()); else return (result); } void init_subrs_a (void) { init_subr_2 ("aref", aref1); init_subr_3 ("aset", aset1); init_lsubr ("string-append", string_append); init_lsubr ("bytes-append", bytes_append); init_subr_1 ("string-length", string_length); init_subr_1 ("string-dimension", string_dim); init_subr_1 ("read-from-string", read_from_string); init_subr_3 ("print-to-string", print_to_string); init_subr_2 ("cons-array", cons_array); init_subr_2 ("sxhash", sxhash); init_subr_2 ("equal?", equal); init_subr_2 ("href", href); init_subr_3 ("hset", hset); init_subr_2 ("assoc", assoc); init_subr_2 ("assv", assv); init_subr_1 ("fast-read", fast_read); init_subr_2 ("fast-print", fast_print); init_subr_2 ("make-list", make_list); init_subr_2 ("fread", lfread); init_subr_2 ("fwrite", lfwrite); init_subr_1 ("fflush", lfflush); init_subr_1 ("length", llength); init_subr_4 ("number->string", number2string); init_subr_2 ("string->number", string2number); init_subr_3 ("substring", substring); init_subr_2 ("string-search", string_search); init_subr_1 ("string-trim", string_trim); init_subr_1 ("string-trim-left", string_trim_left); init_subr_1 ("string-trim-right", string_trim_right); init_subr_1 ("string-upcase", string_upcase); init_subr_1 ("string-downcase", string_downcase); init_subr_2 ("strcmp", lstrcmp); init_subr_2 ("strcat", lstrcat); init_subr_2 ("strcpy", lstrcpy); init_subr_2 ("strbreakup", lstrbreakup); init_subr_2 ("unbreakupstr", lstrunbreakup); init_subr_1 ("string?", stringp); gc_protect_sym (&sym_e, "e"); gc_protect_sym (&sym_f, "f"); gc_protect_sym (&sym_plists, "*plists*"); setvar (sym_plists, arcons (tc_lisp_array, 100, 1), NIL); init_subr_3 ("lref-default", lref_default); init_subr_3 ("larg-default", larg_default); init_subr_3 ("lkey-default", lkey_default); init_lsubr ("list", llist); init_lsubr ("writes", writes); init_subr_3 ("qsort", lqsort); init_subr_2 ("string-lessp", string_lessp); init_lsubr ("mapcar", mapcar); init_subr_3 ("mapcar2", mapcar2); init_subr_2 ("mapcar1", mapcar1); init_subr_3 ("benchmark-funcall1", benchmark_funcall1); init_lsubr ("benchmark-funcall2", benchmark_funcall2); init_subr_3 ("benchmark-eval", benchmark_eval); init_subr_2 ("fmod", lfmod); init_subr_2 ("subset", lsubset); init_subr_1 ("base64encode", base64encode); init_subr_1 ("base64decode", base64decode); init_subr_3 ("ass", ass); init_subr_2 ("append2", append2); init_lsubr ("append", append); init_subr_4 ("fast-save", fast_save); init_subr_2 ("fast-load", fast_load); init_subr_3 ("swrite", swrite); init_subr_2 ("pow", lpow); init_subr_1 ("exp", lexp); init_subr_1 ("log", llog); init_subr_1 ("sin", lsin); init_subr_1 ("cos", lcos); init_subr_1 ("tan", ltan); init_subr_1 ("asin", lasin); init_subr_1 ("acos", lacos); init_subr_1 ("atan", latan); init_subr_2 ("atan2", latan2); init_subr_1 ("typeof", ltypeof); init_subr_1 ("caaar", caaar); init_subr_1 ("caadr", caadr); init_subr_1 ("cadar", cadar); init_subr_1 ("caddr", caddr); init_subr_1 ("cdaar", cdaar); init_subr_1 ("cdadr", cdadr); init_subr_1 ("cddar", cddar); init_subr_1 ("cdddr", cdddr); setvar (cintern ("*pi*"), flocons (atan (1.0) * 4), NIL); init_base64_table (); init_subr_1 ("array->hexstr", hexstr); init_subr_1 ("hexstr->bytes", hexstr2bytes); init_subr_3 ("ass", ass); init_subr_2 ("bit-and", bitand); init_subr_2 ("bit-or", bitor); init_subr_2 ("bit-xor", bitxor); init_subr_1 ("bit-not", bitnot); init_msubr ("cond", leval_cond); init_fsubr ("prog1", leval_prog1); init_subr_2 ("strspn", lstrspn); init_subr_2 ("strcspn", lstrcspn); init_subr_4 ("substring-equal?", substring_equal); init_subr_1 ("butlast", butlast); init_subr_2 ("ash", ash); init_subr_2 ("get", getprop); init_subr_3 ("setprop", setprop); init_subr_3 ("putprop", putprop); init_subr_1 ("last", last); init_subr_2 ("memq", memq); init_subr_2 ("memv", memv); init_subr_2 ("member", member); init_subr_2 ("nth", nth); init_subr_2 ("nconc", nconc); init_subr_2 ("set-eval-history", set_eval_history); init_subr_1 ("parser_fasl", parser_fasl); setvar (cintern ("*parser_fasl.scm-loaded*"), a_true_value (), NIL); init_subr_2 ("parser_fasl_hook", parser_fasl_hook); init_sliba_version (); }