BSD 4_3_Net_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Mon, 14 Dec 1987 11:48:15 +0000 (03:48 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Mon, 14 Dec 1987 11:48:15 +0000 (03:48 -0800)
Work on file usr/src/usr.bin/lisp/franz/lam5.c
Work on file usr/src/usr.bin/lisp/franz/lam7.c
Work on file usr/src/usr.bin/lisp/franz/ffasl.c
Work on file usr/src/usr.bin/lisp/franz/lam8.c
Work on file usr/src/usr.bin/lisp/franz/lam2.c

Synthesized-from: CSRG/cd2/net.2

usr/src/usr.bin/lisp/franz/ffasl.c [new file with mode: 0644]
usr/src/usr.bin/lisp/franz/lam2.c [new file with mode: 0644]
usr/src/usr.bin/lisp/franz/lam5.c [new file with mode: 0644]
usr/src/usr.bin/lisp/franz/lam7.c [new file with mode: 0644]
usr/src/usr.bin/lisp/franz/lam8.c [new file with mode: 0644]

diff --git a/usr/src/usr.bin/lisp/franz/ffasl.c b/usr/src/usr.bin/lisp/franz/ffasl.c
new file mode 100644 (file)
index 0000000..d7f68b9
--- /dev/null
@@ -0,0 +1,606 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: ffasl.c,v 1.11 87/12/14 18:48:06 sklower Exp $";
+#endif
+
+/*                                     -[Mon Mar 21 19:37:21 1983 by jkf]-
+ *     ffasl.c                         $Locker:  $
+ * dynamically load C code
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include "global.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <aout.h>
+#define round(x,s) ((((x)-1) & ~((s)-1)) + (s))
+
+char *stabf = 0, *strcpy(), *Ilibdir();
+extern int fvirgin;
+static seed=0, mypid = 0;
+static char myname[100];
+lispval verify();
+
+/* dispget - get discipline of function
+ * this is used to handle the tricky defaulting of the discipline
+ * field of such functions as cfasl and getaddress.
+ * dispget is given the value supplied by the caller,
+ *     the error message to print if something goes wrong,
+ *     the default to use if nil was supplied.
+ * the discipline can be an atom or string.  If an atom it is supplied
+ * it must be lambda, nlambda or macro.  Otherwise the atoms pname
+ * is used.
+ */
+
+lispval 
+dispget(given,messg,defult)
+lispval given,defult;
+char *messg;
+{
+       int typ;
+
+       while(TRUE)
+       {
+               if(given == nil) 
+                  return(defult);
+               if((typ=TYPE(given)) == ATOM)
+               {  if(given == lambda ||
+                     given == nlambda ||
+                     given == macro) return(given);
+                  else return((lispval) given->a.pname);
+               } else if(typ == STRNG) return(given);
+
+               given = errorh1(Vermisc,messg,nil,TRUE,0,given);
+       }
+}
+
+lispval
+Lcfasl(){
+       register struct argent *mlbot = lbot;
+       register lispval work;
+       register int fildes, totsize;
+       int readsize;
+       lispval csegment();
+       char *sbrk(), *currend, *tfile, cbuf[6000], *mytemp(), *gstab();
+       char ostabf[128];
+       struct exec header;
+       char *largs;
+       Savestack(4);
+
+       switch(np-lbot) {
+          case 3: protect(nil);        /* no discipline given */
+          case 4: protect(nil);        /* no library given  */
+       }
+       chkarg(5,"cfasl");
+       mlbot[0].val = verify(mlbot[0].val,"Incorrect .o file specification");
+       mlbot[1].val = verify(mlbot[1].val,"Incorrect entry specification for cfasl");
+       mlbot[3].val = dispget(mlbot[3].val,"Incorrect discipline specification for cfasl",(lispval)Vsubrou->a.pname);
+       while(TYPE(mlbot[2].val)!= ATOM) 
+       mlbot[2].val = errorh1(Vermisc,"Bad associated atom name for fasl",
+                                                nil,TRUE,0,mlbot[2].val);
+       work = mlbot[4].val;
+       if(work==nil)
+               largs = 0;
+       else 
+               largs = (char *) verify(work,"Bad loader flags");
+
+       /*
+        * Invoke loader.
+        */
+       strcpy(ostabf,gstab());
+       currend = sbrk(0);
+#if (!os_vms) | EUNICE_UNIX_OBJECT_FILE_CFASL
+                       /*** UNIX cfasl code ***/
+       tfile = mytemp();
+       sprintf(cbuf,
+               "%s/nld -N -x -A %s -T %x %s -e %s -o %s %s -lc",
+               Ilibdir(),
+               ostabf,
+               currend,
+               mlbot[0].val,
+               mlbot[1].val,
+               tfile,
+               largs);
+       /* if nil don't print cfasl/nld message */
+       if ( Vldprt->a.clb != nil ) {
+               printf(cbuf);
+               putchar('\n'); fflush(stdout);
+       }
+       if(system(cbuf)!=0) {
+               unlink(tfile);
+               ungstab();
+               fprintf(stderr,"Ld returns error status\n");
+               Restorestack();
+               return(nil);
+       }
+       if(fvirgin)
+               fvirgin = 0;
+       else
+               unlink(ostabf);
+       stabf = tfile;
+       if((fildes = open(tfile,0))<0) {
+               fprintf(stderr,"Couldn't open temporary file: %s\n",tfile);
+               Restorestack();
+               return(nil);
+       }
+       /*
+        * Read a.out header to find out how much room to
+        * allocate and attempt to do so.
+        */
+       if(read(fildes,(char *)&header,sizeof(header)) <= 0) {
+               close(fildes);
+               Restorestack();
+               return(nil);
+       }
+       readsize = round(header.a_text,4) + round(header.a_data,4);
+       totsize  = readsize + header.a_bss;
+       totsize  = round(totsize,512);
+       /*
+        * Fix up system indicators, typing info, etc.
+        */
+       currend = (char *)csegment(OTHER,totsize,FALSE);
+       
+       if(readsize!=read(fildes,currend,readsize))
+               {close(fildes);Restorestack(); return(nil);}
+       work = newfunct();
+       work->bcd.start = (lispval (*)())header.a_entry;
+       work->bcd.discipline = mlbot[3].val;
+       close(fildes);
+       Restorestack();
+       return(mlbot[2].val->a.fnbnd = work);
+#else
+                       /*** VMS cfasl code ***/
+       {
+         int pid = getpid() & 0xffff;  /* Our process ID number */
+         char objfil[100];             /* Absolute object file name */
+         char symfil[100];             /* Old symbol table file */
+         char filename[100];           /* Random filename buffer */
+         int strlen();                 /* String length function */
+         int cvt_unix_to_vms();        /* Convert UNIX to VMS filename */
+         lispval Lgetaddress(),matom();
+         struct stat stbuf;
+
+         if (largs == 0) largs = " ";
+         sprintf(objfil,"tmp:cfasl%d.tmp",pid);
+         symfil[cvt_unix_to_vms(ostabf,symfil)] = 0;
+         sprintf(cbuf,                                 /* Create link cmd. */
+               "$ link/exe=%s/nom/syst=%%X%x/sym=tmp:sym%d.new %s,%s%s",
+               objfil,
+               currend,
+               pid,
+               mlbot[0].val,
+               symfil,
+               largs);
+         printf(                                       /* Echo link cmd. */
+               "$ link/exe=%s/nomap/system=%%X%x/symbol_table=tmp:sym%d.new %s,%s%s\n",
+               objfil,
+               currend,
+               pid,
+               mlbot[0].val,
+               symfil,
+               largs);
+         fflush(stdout);
+         vms_system(cbuf,0);
+
+         if ((fildes = open(objfil,0)) < 0) /* Open abs file */
+               {Restorestack(); return(nil);}
+         fstat(fildes,&stbuf);                         /* Get its size */
+         readsize=stbuf.st_size;
+         currend = (char *)csegment(OTHER,readsize,FALSE);
+         readsize = read(fildes,currend,10000000);
+         close(fildes);
+         /*
+          * Delete the absolute object file
+          */
+         unlink(objfil);
+         /*
+          * Delete the old symbol table (if temporary)
+          */
+         sprintf(filename,"tmp:sym%d.stb",pid);
+         unlink(filename);
+         /*
+          * Rename the new symbol table so it is now the old symbol table
+          */
+         sprintf(symfil,"tmp:sym%d.new",pid);
+         link(symfil,filename);
+         unlink(symfil);
+         sprintf(myname,"tmp:sym%d.stb",pid);
+         stabf = myname;
+         /*
+          * Return  Lgetaddress(entry,function_name,discipline)
+          */
+         {
+            struct argent *oldlbot, *oldnp;
+            lispval result;
+
+            oldlbot = lbot;
+            oldnp = np;
+            lbot = np;
+            np++->val = matom(mlbot[1].val);
+            np++->val = mlbot[2].val;
+            np++->val = matom(mlbot[3].val);
+            result = Lgetaddress();
+            lbot = oldlbot;
+            np = oldnp;
+            return(result);
+         }
+       }
+#endif
+}
+#ifdef os_vms
+#define M 4
+#else
+#define M 1
+#endif
+#define oktox(n) \
+       (0==stat(n,&stbuf)&&(stbuf.st_mode&S_IFMT)==S_IFREG&&0==access(n,M))
+char *
+gstab()
+{
+       register char *cp, *cp2; char *getenv();
+       struct stat stbuf;
+       extern char **Xargv;
+
+       if(stabf==0) {
+               cp = getenv("PATH");
+               if(cp==0)
+                       cp=":/usr/ucb:/bin:/usr/bin";
+               if(*cp==':'||*Xargv[0]=='/') {
+                       cp++;
+                       if(oktox(Xargv[0])) {
+                               strcpy(myname,Xargv[0]);
+                               return(stabf = myname);
+                       }
+#ifdef os_vms
+                       /*
+                        *      Try Xargv[0] with ".stb" concatenated
+                        */
+                       strcpy(myname,Xargv[0]);
+                       strcat(myname,".stb");
+                       if (oktox(myname)) return(stabf = myname);
+                       /*
+                        *      Try Xargv[0] with ".exe" concatenated
+                        */
+                       strcpy(myname,Xargv[0]);
+                       strcat(myname,".exe");
+                       if (oktox(myname)) return(stabf = myname);
+#endif
+               }
+               for(;*cp;) {
+
+                       /* copy over current directory
+                          and then append argv[0] */
+
+                       for(cp2=myname;(*cp)!=0 && (*cp)!=':';)
+                               *cp2++ = *cp++;
+                       *cp2++ = '/';
+                       strcpy(cp2,Xargv[0]);
+                       if(*cp) cp++;
+#ifndef        os_vms
+                       if(!oktox(myname)) continue;
+#else
+                       /*
+                        *      Also try ".stb" and ".exe" in VMS
+                        */
+                       if(!oktox(myname)) {
+                               char *end_of_name;
+                               end_of_name = cp2 + strlen(cp2);
+                               strcat(cp2,".stb");
+                               if(!oktox(myname)) {
+                                       /*
+                                        *      Try ".exe"
+                                        */
+                                       *end_of_name = 0;   /* Kill ".stb" */
+                                       strcat(cp2,".exe");
+                                       if (!oktox(myname)) continue;
+                               }
+                       }
+#endif
+                       return(stabf = myname);
+               }
+               /* one last try for dual systems */
+               strcpy(myname,Xargv[0]);
+               if(oktox(myname)) return(stabf = myname);
+               error("Could not find which file is being executed.",FALSE);
+               /* NOTREACHED */
+       } else return (stabf);
+}
+static char mybuff[40]; 
+char *
+mytemp()
+{
+       /*if(mypid==0) mypid = (getpid() & 0xffff);
+         fails if you do a dumplisp after doing a
+         cfasl */
+       sprintf(mybuff,"/tmp/Li%d.%d",(getpid() & 0xffff),seed++);
+       return(mybuff);
+}
+ungstab()
+{
+       seed--;
+       sprintf(mybuff,"/tmp/Li%d.%d",(getpid() & 0xffff),seed-1);
+       if(seed==0) {
+               stabf = 0;
+               fvirgin = 1;
+       }
+}
+lispval
+verify(in,error)
+register lispval in;
+char *error;
+{
+       for(EVER) {
+               switch(TYPE(in)) {
+               case STRNG:
+                       return(in);
+               case ATOM:
+                       return((lispval)in->a.pname);
+               }
+               in = errorh1(Vermisc,error,nil,TRUE,0,in);
+       }
+}
+
+
+/* extern      int fvirgin; */
+                       /* declared in ffasl.c tells if this is original
+                        *      lisp symbol table.
+                        * if fvirgin is 1 then we must copy the symbol
+                        *      table, else we can overwrite it, since
+                        *      it is a temporary file which only
+                        *      one user could be using(was not created
+                        *      as an original lisp or by a (dumplisp)
+                        *      or a (savelisp)).
+                        */
+
+/* copy a block of data from one file to another of size size */
+copyblock(f1,f2,size)
+FILE *f1, *f2;
+long size;
+{
+       char block[BUFSIZ];
+
+           while ( size > BUFSIZ ) {
+               size -= BUFSIZ;
+               fread(block,BUFSIZ,1,f1);
+               fwrite(block,BUFSIZ,1,f2);
+           }
+           if (size > 0 ) {
+               fread(block,(int)size,1,f1);
+               fwrite(block,(int)size,1,f2);
+           }
+}
+
+/* removeaddress --
+ *
+ * (removeaddress '|_entry1| '|_entry2| ...)
+ *
+ *     removes the given entry points from the run time symbol table,
+ *             so that later cfasl'd files can have these label names.
+ *
+ */
+
+lispval
+Lrmadd(){
+       register struct argent *mlbot = lbot;
+       register struct nlist *q; 
+       register int i;
+       int numberofargs, strsize;
+       char *gstab();
+       char ostabf[128];
+       char *nstabf,*mytemp();
+       char *strtbl,*alloca();
+       int i2, n, m, nargleft, savem;
+       FILE *f, *fa;
+       FILE *fnew;
+       off_t savesymadd,symadd;                /* symbol address */
+       struct exec buf;
+       struct nlist nlbuf[BUFSIZ/sizeof (struct nlist)];
+       int maxlen;
+       int change;
+       Keepxs();
+
+       numberofargs = (np - lbot);
+       nargleft = numberofargs;
+       maxlen = 0;
+       for ( i=0; i<numberofargs; i++,mlbot ++) {
+               mlbot->val = verify(mlbot->val,"Incorrect entry specification.");
+               n = strlen((char *)mlbot->val);
+               if (n > maxlen)
+                       maxlen = n;
+       }
+       /* 
+        *  Must not disturb object file if it an original file which
+        *      other users can execute(signified by the variable fvirgin).
+        *      so the entire symbol table is copied to a new file.
+        */
+       if (fvirgin) {
+               strncpy(ostabf,gstab(),128);
+               nstabf = mytemp();
+               /*
+                * copy over symbol table into a temporary file first
+                *
+                */
+               f = fopen(ostabf, "r");
+               fnew = fopen(nstabf, "w");
+               if (( f == NULL ) || (fnew == NULL)) {Freexs(); return( nil );}
+               /* read exec header on file */
+#ifndef        os_vms
+               fread((char *)&buf, sizeof buf, 1, f);
+#else  os_vms
+               /*
+                *      Under VMS/EUNICE we have to try the 1st 512 byte
+                *      block and the 2nd 512 byte block (there may be
+                *      a VMS header in the 1st 512 bytes).
+                */
+               get_aout_header(fileno(f),&buf);
+#endif os_vms
+
+               /* Is this a legitimate a.out file? */
+               if (N_BADMAG(buf)) {
+                       unlink(nstabf);
+                       ungstab();
+                       fclose(f);
+                       fclose(fnew);
+                       errorh1(Vermisc,"Removeaddress: Bad file",nil,FALSE,0,inewstr(ostabf));
+                       {Freexs(); return(nil);}
+               }
+               /* set pointer on read file to symbol table */
+               /* must be done before the structure buf is reassigned 
+                * so that it will be accurate for the read file 
+                */
+               fseek(f,(long)N_SYMOFF(buf),0);
+               /* reset up exec header structure for new file */
+               buf.a_magic = OMAGIC;
+               buf.a_text = 0;
+               buf.a_data = 0;
+               buf.a_bss = 0;
+               buf.a_entry = 0;
+               buf.a_trsize = 0;
+               buf.a_drsize = 0;
+               fwrite((char *)&buf,
+                      sizeof buf,1,fnew);      /* write out exec header */
+               copyblock(f,fnew,(long)buf.a_syms); /* copy symbol table */
+#if ! (os_unisoft | os_unix_ts)
+               fread((char *)&strsize,
+                     sizeof (int),1,f);        /* find size of string table */
+               fwrite((char *)&strsize,
+                     sizeof (int),1,fnew);     /* find size of string table */
+               strsize -= 4;
+               strtbl = alloca(strsize);
+               fread(strtbl,strsize,1,f);      /* read and save string table*/
+               fwrite(strtbl,strsize,1,fnew);  /* copy out string table     */
+#endif
+               fclose(f);fclose(fnew);
+       } else {
+               nstabf = gstab();
+       }
+
+       /*
+        * now unset the external bits it the entry points specified.
+        */
+       f = fopen(nstabf, "r");
+       fa = fopen(nstabf, "a");
+       if (( f == NULL ) || (fa == NULL)) {
+               unlink(nstabf);
+               ungstab();
+               if (f != NULL ) fclose(f);
+               if (fa != NULL ) fclose(fa);
+               return ( nil );
+       }
+
+       /* read exec header on file */
+#ifndef        os_vms
+       fread((char *)&buf, sizeof buf, 1, f);
+#else  os_vms
+       /*
+        *      Under VMS/EUNICE we have to try the 1st 512 byte
+        *      block and the 2nd 512 byte block (there may be
+        *      a VMS header in the 1st 512 bytes).
+        */
+       get_aout_header(fileno(f),&buf);
+#endif os_vms
+
+       /* Is this a legitimate a.out file? */
+       if (N_BADMAG(buf)) {
+               if (fvirgin) {
+                       unlink(nstabf);
+                       ungstab();
+               }
+               fclose(f);
+               fclose(fa);
+               errorh1(Vermisc,"Removeaddress: Bad file",nil,FALSE,0,inewstr(ostabf));
+               {Freexs(); return(nil);}
+       } else {
+               symadd = N_SYMOFF(buf);
+#if ! (os_unisoft | os_unix_ts)
+               /*
+                * read in string table if not done during copying
+                */
+               if (fvirgin==0){
+                       fseek(f,(long)N_STROFF(buf),0);
+                       fread((char *)&strsize,sizeof (int),1,f);
+                       strsize -= 4;
+                       strtbl = alloca(strsize);
+                       fread(strtbl,strsize,1,f);
+               }
+#endif
+               n = buf.a_syms;
+               fseek(f, (long)symadd, 0);
+               while (n) {
+                       m = sizeof (nlbuf);
+                       if (n < m)
+                               m = n;
+
+                       /* read next block of symbols from a.out file */
+                       fread((char *)nlbuf, m, 1, f);
+                       savem = m;
+                       savesymadd = symadd;
+                       symadd += m;
+                       n -= m;
+                       change = 0;
+
+               /* compare block of symbols against list of entry point
+                *      names given, if a match occurs, clear the N_EXT bit
+                *      for that given symbol and signal a change.
+                */
+                       for (q = nlbuf; (m -= sizeof(struct nlist)) >= 0; q++) {
+
+              /* make sure it is external */
+                               if (
+                                   (q->n_type & N_EXT)==0
+#if ! (os_unix_ts | os_unisoft)
+                                   || q->n_un.n_strx == 0 || q->n_type & N_STAB
+#endif
+                                  )    continue;
+                       for (mlbot=lbot,i2 = 0;i2<numberofargs;i2++,mlbot++) {
+#if ! (os_unix_ts | os_unisoft)
+                               if(strcmp((char *)mlbot->val,
+                                         strtbl+q->n_un.n_strx-4)!=0)
+                                               continue;
+#else
+                               if(strncmp((char *)mlbot->val,
+                                          q->n_name,8)!=0)
+                                               continue;
+#endif
+                               change = 1;
+                               q->n_type &= ~N_EXT;
+                               break;
+                       }
+               }
+               if ( change ) {
+                       fseek(fa,(long)savesymadd,0);
+                       fwrite((char *)nlbuf, savem, 1, fa);
+                       if (--nargleft == 0)
+                               goto alldone;
+               }
+               }
+       }
+alldone:
+       fclose(f);
+       fclose(fa);
+       if(fvirgin)
+               fvirgin = 0;
+       stabf = nstabf;
+       {Freexs(); return(tatom);}
+}
+char *
+Ilibdir()
+{
+       register lispval handy;
+tryagain:
+       handy = Vlibdir->a.clb;
+       switch(TYPE(handy)) {
+       case ATOM:
+               handy = (lispval) handy->a.pname;
+       case STRNG:
+               break;
+       default:
+               (void) error(
+"cfasl or load: lisp-library-directory not bound to string or atom",
+                               TRUE);
+               goto tryagain;
+       }
+       return((char *) handy);
+}
diff --git a/usr/src/usr.bin/lisp/franz/lam2.c b/usr/src/usr.bin/lisp/franz/lam2.c
new file mode 100644 (file)
index 0000000..6a36f5e
--- /dev/null
@@ -0,0 +1,695 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: lam2.c,v 1.6 87/12/14 18:48:13 sklower Exp $";
+#endif
+
+/*                                     -[Fri Aug  5 12:46:16 1983 by jkf]-
+ *     lam2.c                          $Locker:  $
+ * lambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+# include "global.h"
+# include <signal.h>
+# include "structs.h"
+# include "chars.h"
+# include "chkrtab.h"
+/*
+ * (flatc 'thing ['max]) returns the smaller of max and the number of chars
+ * required to print thing linearly.
+ * if max argument is not given, we assume the second arg is infinity
+ */
+static flen; /*Internal to this module, used as a running counter of flatsize*/
+static fmax; /*used for maximum for quick reference */
+char *strcpy();
+
+lispval
+Lflatsi()
+{
+       register lispval current;
+       Savestack(1);                   /* fixup entry mask */
+
+       fmax = 0x7fffffff;      /* biggest integer by default */
+       switch(np-lbot) 
+       {
+           case 2: current = lbot[1].val;
+                   while(TYPE(current) != INT)
+                       current = errorh1(Vermisc,
+                                       "flatsize: second arg not integer",
+                                       nil,TRUE,0,current);
+                   fmax = current->i;
+           case 1: break;
+           default: argerr("flatsize");
+       }
+
+       flen = 0; 
+       current = lbot->val;
+       protect(nil);                   /*create space for argument to pntlen*/
+       Iflatsi(current);
+       Restorestack();
+       return(inewint(flen));
+}
+/*
+ * Iflatsi does the real work of the calculation for flatc
+ */
+Iflatsi(current)
+register lispval current;
+{
+
+       if(flen > fmax) return;
+       switch(TYPE(current)) {
+
+       patom:
+       case INT: case ATOM: case DOUB: case STRNG:
+               np[-1].val = current;
+               flen += Ipntlen();
+               return;
+       
+       pthing:
+       case DTPR:
+               flen++;
+               Iflatsi(current->d.car);
+               current = current->d.cdr;
+               if(current == nil) {
+                       flen++;
+                       return;
+               }
+               if(flen > fmax) return;
+               switch(TYPE(current)) {
+               case INT: case ATOM: case DOUB:
+                       flen += 4;
+                       goto patom;
+               case DTPR:
+                       goto pthing;
+               }
+       }
+}
+
+
+#define EADC -1
+#define EAD  -2
+lispval
+Lread()
+{ return (r(EAD)); }
+
+lispval
+Lratom()
+{ return (r(ATOM)); }
+
+lispval
+Lreadc()
+{ return (r(EADC)); }
+
+
+extern unsigned char *ctable;
+/* r *********************************************************************/
+/* this function maps the desired read         function into the system-defined */
+/* reading functions after testing for a legal port.                    */
+lispval
+r(op)
+int op;
+{
+       unsigned char c; register lispval result;
+       register cc;
+       int orlevel; extern int rlevel;
+       FILE *ttemp;
+       struct nament *oldbnp = bnp;
+       Savestack(2);
+
+       switch(np-lbot) {
+       case 0:
+               protect(nil);
+       case 1:
+               protect(nil);
+       case 2: break;
+       default:
+               argerr("read or ratom or readc");
+       }
+       result = Vreadtable->a.clb;
+       chkrtab(result);
+       orlevel = rlevel;
+       rlevel = 0;
+       ttemp = okport(Vpiport->a.clb,stdin);
+       ttemp = okport(lbot->val,ttemp);
+/*printf("entering switch\n");*/
+       if(ttemp == stdin) fflush(stdout);      /* flush any pending 
+                                                * characters if reading stdin 
+                                                * there should be tests to see
+                                                * if this is a tty or pipe
+                                                */
+
+       switch (op)
+       {
+       case EADC:      rlevel = orlevel;
+                       cc = getc(ttemp);
+                       c = cc;
+                       if(cc == EOF)
+                       {
+                               Restorestack();
+                               return(lbot[1].val);
+                       } else {
+                               strbuf[0] = hash = (c & 0177);
+                               strbuf[1] = 0;
+                               atmlen = 2;
+                               Restorestack();
+                               return((lispval)getatom(TRUE));
+                       }
+
+       case ATOM:      rlevel = orlevel;
+                       result = (ratomr(ttemp));
+                       goto out;
+
+       case EAD:       PUSHDOWN(Vpiport,P(ttemp)); /* rebind Vpiport */
+                       result = readr(ttemp);
+       out:            if(result==eofa)
+                       {    
+                            if(sigintcnt > 0) sigcall(SIGINT);
+                            result = lbot[1].val;
+                       }
+                       rlevel = orlevel;
+                       popnames(oldbnp);       /* unwind bindings */
+                       Restorestack();
+                       return(result);
+       }
+       /* NOTREACHED */
+}
+
+/* Lload *****************************************************************/
+/* Reads in and executes forms from the specified file. This should      */
+/* really be an nlambda taking multiple arguments, but the error        */
+/* handling gets funny in that case (one file out of several not        */
+/* openable, for instance).                                             */
+lispval
+Lload()
+{
+       register FILE *port;
+       register char *p, *ttemp; register lispval vtemp;
+       struct nament *oldbnp = bnp;
+       int orlevel,typ;
+       char longname[100];
+       char *shortname, *end2, *Ilibdir();
+       /*Savestack(4); not necessary because np not altered */
+
+       chkarg(1,"load");
+       if((typ = TYPE(lbot->val)) == ATOM)
+           ttemp =  lbot->val->a.pname ;  /* ttemp will point to name */
+       else if(typ == STRNG)
+           ttemp = (char *) lbot->val;
+       else 
+            return(error("FILENAME MUST BE ATOMIC",FALSE));
+       strcpy(longname, Ilibdir());
+       for(p = longname; *p; p++);
+       *p++ = '/'; *p = 0;
+       shortname = p;
+       strcpy(p,ttemp);
+       for(; *p; p++);
+               end2 = p;
+       strcpy(p,".l");
+       if ((port = fopen(shortname,"r")) == NULL &&
+               (port = fopen(longname, "r")) == NULL) {
+                       *end2 = 0;
+                       if ((port = fopen(shortname,"r")) == NULL &&
+                               (port = fopen(longname, "r")) == NULL)
+                                       errorh1(Vermisc,"Can't open file: ", 
+                                                    nil,FALSE,0,lbot->val);
+       }
+       orlevel = rlevel;
+       rlevel = 0;
+
+       if(ISNIL(copval(gcload,CNIL)) &&
+               loading->a.clb != tatom &&
+               ISNIL(copval(gcdis,CNIL)))
+               gc((struct types *)CNIL);    /*  do a gc if gc will be off  */
+
+       /* shallow bind the value of lisp atom piport   */
+       /* so readmacros will work                      */
+       PUSHDOWN(Vpiport,P(port));
+       PUSHDOWN(loading,tatom);        /* set indication of loading status */
+
+       while ((vtemp = readr(port)) != eofa) {
+           eval(vtemp);
+       }
+       popnames(oldbnp);               /* unbind piport, loading */
+
+       rlevel = orlevel;
+       fclose(port);
+       return(nil);
+}
+
+/* concat **************************************************
+-
+-  use: (concat arg1 arg2 ... )
+-
+-  concatenates the print names of all of its arguments.
+- the arguments may be atoms, integers or real numbers.
+-
+- *********************************************************/
+lispval
+Iconcat(unintern)
+{
+       register struct argent *temnp;
+       register char *cp = strbuf;
+       register lispval cur;
+       int n;
+       char *atomtoolong();
+       lispval Lhau();
+
+       *cp = NULL_CHAR ;
+
+       /* loop for each argument */
+       for(temnp = lbot + AD ; temnp < np ; temnp++)
+       {
+           cur = temnp->val;
+           switch(TYPE(cur))
+           {
+           case ATOM:
+                n = strlen(cur->a.pname);
+                while(n + cp >= endstrb) cp = atomtoolong(cp);
+                strcpy(cp, cur->a.pname);
+                cp += n;
+                break;
+
+           case STRNG:
+                n = strlen( (char *) cur);
+                while(n + cp >= endstrb) cp = atomtoolong(cp);
+                strcpy(cp, (char *) cur);
+                cp += n;
+                break;
+
+           case INT:
+                if(15 + cp >= endstrb) cp = atomtoolong(cp);
+                sprintf(cp,"%d",cur->i);
+                while(*cp) cp++;
+                break;
+
+           case DOUB:
+                if(15 + cp >= endstrb) cp = atomtoolong(cp);
+                sprintf(cp,"%f",cur->f);
+                while(*cp) cp++;
+                break;
+
+           case SDOT: {
+               struct _iobuf _myiob;
+               register lispval handy = cur;
+
+               for(n = 12; handy->s.CDR!=(lispval) 0; handy = handy->s.CDR)
+                       n += 12;
+
+               while(n + cp >= endstrb) cp = atomtoolong(cp);
+
+               _myiob._flag = _IOWRT+_IOSTRG;
+               _myiob._ptr = cp;
+               _myiob._cnt = endstrb - cp - 1;
+
+               pbignum(cur,&_myiob);
+               cp = _myiob._ptr;
+               *cp = 0;
+               break; }
+                   
+           default:
+                cur = error("Non atom or number to concat",TRUE);
+                continue;    /* if returns value, try it */
+          }
+
+       }
+
+       if(unintern)
+               return( (lispval) newatom(FALSE)); /* uninterned atoms may
+                                                       have printname gc'd*/
+       else
+               return( (lispval) getatom(FALSE)) ;
+}
+lispval
+Lconcat(){
+       return(Iconcat(FALSE));
+}
+lispval
+Luconcat(){
+       return(Iconcat(TRUE));
+}
+
+lispval
+Lputprop()
+{
+       lispval Iputprop();
+       chkarg(3,"putprop");
+       return(Iputprop(lbot->val,lbot[1].val,lbot[2].val));
+}
+
+/*
+ * Iputprop :internal version of putprop used by some C functions
+ *  note: prop and ind are lisp values but are not protected (by this
+ * function) from gc.  The caller should protect them!!
+ */
+lispval
+Iputprop(atm,prop,ind)
+register lispval prop, ind, atm;
+{
+       register lispval pptr;
+       lispval *tack;          /* place to begin property list */
+       lispval pptr2;
+       lispval errorh();
+       Savestack(4);
+       
+ top:
+       switch (TYPE(atm)) {
+       case ATOM:
+               if(atm == nil) tack = &nilplist;
+               else tack =  &(atm->a.plist);
+               break;
+       case DTPR:
+               for (pptr = atm->d.cdr ; pptr != nil ; pptr = pptr->d.cdr->d.cdr)
+                   if(TYPE(pptr) != DTPR || TYPE(pptr->d.cdr) != DTPR) break;
+               if(pptr != nil) 
+               {   atm = errorh1(Vermisc,
+                                "putprop: bad disembodied property list",
+                                nil,TRUE,0,atm);
+                   goto top;
+               }
+               tack = (lispval *) &(atm->d.cdr);
+               break;
+       default:
+               errorh1(Vermisc,"putprop: Bad first argument: ",nil,FALSE,0,atm);
+       }
+       pptr = *tack;   /* start of property list */
+/*findit:*/
+       for (pptr = *tack ; pptr != nil ; pptr = pptr->d.cdr->d.cdr)
+               if (pptr->d.car == ind) {
+                       (pptr->d.cdr)->d.car = prop;
+                       Restorestack();
+                       return(prop);
+               }
+       /* not found, add to front
+          be careful, a gc could occur before the second newdot() */
+          
+       pptr = newdot();
+       pptr->d.car = prop;
+       pptr->d.cdr = *tack;
+       protect(pptr);
+       pptr2 = newdot();
+       pptr2->d.car = ind;
+       pptr2->d.cdr = pptr;
+       *tack = pptr2;
+       Restorestack();
+       return(prop);
+}
+
+/* get from property list 
+ *   there are three routines to accomplish this
+ *     Lget - lisp callable, the first arg can be a symbol or a disembodied
+ *           property list.  In the latter case we check to make sure it
+ *           is a real one (as best we can).
+ *     Iget - internal routine, the first arg must be a symbol, no disembodied
+ *           plists allowed
+ *     Igetplist - internal routine, the first arg is the plist to search.
+ */
+lispval
+Lget()
+{
+       register lispval ind, atm;
+       register lispval dum1;
+       lispval Igetplist();
+
+       chkarg(2,"get");
+       ind = lbot[1].val;
+       atm = lbot[0].val;
+top:
+       switch(TYPE(atm)) {
+       case ATOM:
+               if(atm==nil) atm = nilplist;
+               else atm = atm->a.plist;
+               break;          
+
+       case DTPR:
+               for (dum1 = atm->d.cdr; dum1 != nil; dum1 = dum1->d.cdr->d.cdr)
+                   if((TYPE(dum1) != DTPR) || 
+                      (TYPE(dum1->d.cdr) != DTPR)) break; /* bad prop list */
+               if(dum1 != nil) 
+               {   atm = errorh1(Vermisc,
+                                "get: bad disembodied property list",
+                                nil,TRUE,0,atm);
+                   goto top;
+               }
+               atm = atm->d.cdr;
+               break;
+       default:
+               /* remove since maclisp doesnt treat
+                  this as an error, ugh
+                  return(errorh1(Vermisc,"get: bad first argument: ",
+                              nil,FALSE,0,atm));
+                */
+                return(nil);
+       }
+
+       while (atm != nil)
+               {
+                       if (atm->d.car == ind)
+                               return ((atm->d.cdr)->d.car);
+                       atm = (atm->d.cdr)->d.cdr;
+               }
+       return(nil);
+}
+/*
+ * Iget - the first arg must be a symbol.
+ */
+       
+lispval
+Iget(atm,ind)
+register lispval atm, ind;
+{
+       lispval Igetplist();
+
+       if(atm==nil)
+               atm = nilplist;
+       else
+               atm = atm->a.plist;
+       return(Igetplist(atm,ind));
+}
+
+/*
+ *  Igetplist
+ * pptr is a plist
+ * ind is the indicator
+ */
+
+lispval
+Igetplist(pptr,ind)
+register lispval pptr,ind;
+{
+       while (pptr != nil)
+               {
+                       if (pptr->d.car == ind)
+                               return ((pptr->d.cdr)->d.car);
+                       pptr = (pptr->d.cdr)->d.cdr;
+               }
+       return(nil);
+}
+lispval
+Lgetd()
+{
+       register lispval typ;
+       
+       chkarg(1,"getd");
+       typ = lbot->val;
+       if (TYPE(typ) != ATOM) 
+          errorh1(Vermisc,
+                 "getd: Only symbols have function definitions",
+                 nil,
+                 FALSE,
+                 0,
+                 typ);
+       return(typ->a.fnbnd);
+}
+lispval
+Lputd()
+{
+       register lispval atom, list;
+       
+       chkarg(2,"putd");
+       list = lbot[1].val;
+       atom = lbot->val;
+       if (TYPE(atom) != ATOM) error("only symbols have function definitions",
+                                       FALSE);
+       atom->a.fnbnd = list;
+       return(list);
+}
+
+/* ===========================================================
+- mapping functions which return a list of the answers
+- mapcar applies the given function to successive elements
+- maplist applies the given function to successive sublists
+- ===========================================================*/
+
+lispval
+Lmapcrx(maptyp,join)
+int maptyp;            /* 0 = mapcar,  1 = maplist  */
+int join;              /* 0 = the above, 1 = s/car/can/ */
+{
+       register struct argent *namptr;
+       register index;
+       register lispval temp;
+       register lispval current;
+
+       struct argent *first, *last;
+       int count;
+       lispval lists[25], result;
+       Savestack(4);
+       
+       namptr = lbot + 1;
+       count = np - namptr;
+       if (count <= 0) return (nil);
+       result = current =  (lispval) np;
+       protect(nil);                   /* set up space for returned list */
+       protect(lbot->val);     /*copy funarg for call to funcall */
+       lbot = np -1;
+       first = np;
+       last = np += count;
+       for(index = 0; index < count; index++) {
+               temp =(namptr++)->val; 
+               if (TYPE (temp ) != DTPR && temp!=nil) 
+                       error ( "bad list argument to map",FALSE);
+               lists[index] = temp;
+       }
+       for(;;) {
+               for(namptr=first,index=0; index<count; index++) {
+                       temp = lists[index];
+                       if(temp==nil) goto done;
+
+                       if(maptyp==0) (namptr++)->val = temp->d.car;
+                       else (namptr++)->val = temp;
+
+                       lists[index] = temp->d.cdr;
+               }
+               if (join == 0) {
+                       current->l = newdot();
+                       current->l->d.car = Lfuncal();
+                       current = (lispval) &current->l->d.cdr;
+               } else {
+                       current->l = Lfuncal();
+                       if ( TYPE ( current -> l) != DTPR && current->l != nil)
+                               error("bad type returned from funcall inside map",FALSE);
+                       else  while ( current -> l  != nil )
+                                       current = (lispval) & (current ->l ->d.cdr);
+               }
+               np = last;
+       }
+done:  if (join == 0)current->l = nil;
+       Restorestack();
+       return(result->l);
+}
+
+/* ============================
+-
+- Lmapcar
+- =============================*/
+
+lispval
+Lmpcar()
+{
+       return(Lmapcrx(0,0));   /* call general routine */
+}
+
+
+/* ============================
+-
+-
+-  Lmaplist
+- ==============================*/
+
+lispval
+Lmaplist()
+{
+       return(Lmapcrx(1,0));   /* call general routine */
+}
+
+
+/* ================================================
+- mapping functions which return the value of the last function application.
+- mapc and map
+- ===================================================*/
+
+lispval
+Lmapcx(maptyp)
+int maptyp;            /* 0= mapc   , 1= map  */
+{
+       register struct argent *namptr;
+       register index;
+       register lispval temp;
+       register lispval result;
+
+       int count;
+       struct argent *first;
+       lispval lists[25], errorh();
+       Savestack(4);
+       
+       namptr = lbot + 1;
+       count = np - namptr;
+       if(count <= 0) return(nil);
+       result = lbot[1].val;           /*This is what macsyma wants so ... */
+                                       /*copy funarg for call to funcall */
+       lbot = np; protect((namptr - 1)->val);
+       first = np; np += count;
+
+       for(index = 0; index < count; index++) {
+               temp = (namptr++)->val;
+               while(temp!=nil && TYPE(temp)!=DTPR)
+                       temp = errorh1(Vermisc,"Inappropriate list argument to mapc",nil,TRUE,0,temp);
+               lists[index] = temp;
+       }
+       for(;;) {
+               for(namptr=first,index=0; index<count; index++) {
+                       temp = lists[index];
+                       if(temp==nil)
+                               goto done;
+                       if(maptyp==0)
+                               (namptr++)->val = temp->d.car;
+                       else
+                               (namptr++)->val = temp;
+                       lists[index] = temp->d.cdr;
+               }
+               Lfuncal();
+       }
+done:  
+       Restorestack();
+       return(result);
+}
+
+
+/* ==================================
+-
+-      mapc   map the car of the lists
+-
+- ==================================*/
+
+lispval
+Lmapc()
+{      return( Lmapcx(0) );  }
+
+
+/* =================================
+-
+-      map    map the cdr of the lists
+-
+- ===================================*/
+
+lispval
+Lmap()
+{      return( Lmapcx(1) );   }
+
+
+lispval
+Lmapcan()
+{ 
+       lispval Lmapcrx();
+
+       return ( Lmapcrx ( 0,1 ) ); 
+} 
+
+lispval
+Lmapcon()
+{ 
+       lispval Lmapcrx();
+
+       return ( Lmapcrx ( 1,1 ) ); 
+}
diff --git a/usr/src/usr.bin/lisp/franz/lam5.c b/usr/src/usr.bin/lisp/franz/lam5.c
new file mode 100644 (file)
index 0000000..1152368
--- /dev/null
@@ -0,0 +1,579 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: lam5.c,v 1.8 87/12/14 18:47:45 sklower Exp $";
+#endif
+
+/*                                     -[Fri Aug  5 12:49:06 1983 by jkf]-
+ *     lam5.c                          $Locker:  $
+ * lambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#include "chkrtab.h"
+#include <ctype.h>
+char *strcpy();
+
+/*===========================================
+-
+-      explode functions: aexplode , aexplodec, aexploden
+- The following function partially implement the explode functions for atoms.
+-  The full explode functions are written in lisp and call these for atom args.
+-
+-===========================================*/
+
+#include "chars.h"
+lispval
+Lexpldx(kind,slashify)
+int kind, slashify;    /* kind = 0 => explode to characters 
+                               = 1 => explode to fixnums (aexploden)
+                          slashify = 0 => do not quote bizarre characters
+                                   = 1 => quote bizarre characters
+                       */
+{
+       int typ, i;
+       char ch, *strb, strbb[BUFSIZ], *alloca();  /* temporary string buffer */
+       register lispval last, handy;
+       extern int uctolc;
+       register char *cp;
+       Savestack(3); /* kludge register save mask */
+#ifdef SPISFP
+       Keepxs();
+#endif
+
+       chkarg(1,"expldx");
+
+       handy = Vreadtable->a.clb;
+       chkrtab(handy);
+       handy = lbot->val;
+       *strbuf = 0;
+       typ=TYPE(handy);        /* we only work for a few types */
+
+
+       /* put the characters to return in the string buffer strb */
+
+       switch(typ) {
+       case STRNG:
+               if(slashify && !Xsdc)
+                   errorh1(Vermisc,"Can't explode without string delimiter",nil
+                                         ,FALSE,0,handy);
+               
+               strb = strbb;
+               if(slashify) *strb++ = Xsdc;
+               /* copy string into buffer, escape only occurances of the 
+                  double quoting character if in slashify mode
+               */
+               for(cp = (char *) handy; *cp; cp++)
+               {
+                 if(slashify &&
+                    (*cp == Xsdc || synclass(ctable[*cp])==CESC))
+                        *strb++ = Xesc;
+                 *strb++ = *cp;
+               }
+               if(slashify) *strb++ = Xsdc;
+               *strb = NULL_CHAR ;
+               strb = strbb;
+               break;
+
+       case ATOM:
+               strb = handy->a.pname;
+               if(slashify && (strb[0]==0)) {
+                       strb = strbb;
+                       strbb[0] = Xdqc;
+                       strbb[1] = Xdqc;
+                       strbb[2] = 0;
+               } else
+       /*common:*/
+               if(slashify != 0)
+               {
+                       char *out = strbb;
+                       unsigned char code;
+
+                       cp = strb;
+                       strb = strbb;
+                       code = ctable[(*cp)&0177];
+                       switch(synclass(code)) {
+                       case CNUM:
+                               *out++ = Xesc;
+                               break;
+                       case CCHAR:
+                               if(uctolc && isupper((*cp)&0177)) {
+                                   *out++ = Xesc;
+                               }
+                               break;
+                       default:
+                           switch(code&QUTMASK) {
+                           case QWNUNIQ:
+                                   if (cp[1]==0) *out++ = Xesc;
+                                   break;
+                           case QALWAYS:
+                           case QWNFRST:
+                                   *out++ = Xesc;
+                           }
+                       }
+                       *out++ = *cp++;
+                       for(; *cp; cp++)
+                       {
+                               if(((ctable[*cp]&QUTMASK)==QALWAYS) ||
+                                  (uctolc && isupper(*cp)))
+                                       *out++ = Xesc;
+                               *out++ = *cp;
+                       }
+                       *out = 0;
+               }
+               break;
+                               
+       case INT:
+               strb = strbb;
+               sprintf(strb, "%d", lbot->val->i);
+               break;
+       case DOUB:
+               strb = strbb;
+               lfltpr(strb, lbot->val->r);
+               break;
+       case SDOT:
+       {
+               struct _iobuf _strbuf;
+               int count;
+               for((handy = lbot->val), count = 12;
+                   handy->s.CDR!=(lispval) 0;
+                   (handy = handy->s.CDR), count += 12);
+               strb = alloca(count);
+
+               _strbuf._flag = _IOWRT+_IOSTRG;
+               _strbuf._ptr = strb;
+               _strbuf._cnt = count;
+               pbignum(lbot->val,&_strbuf);
+               putc(0,&_strbuf);
+               break;
+       }
+       default:
+                       errorh1(Vermisc,"EXPLODE ARG MUST BE STRING, SYMBOL, FIXNUM, OR FLONUM",nil,FALSE,0,handy);
+                       Restorestack();
+                       Freexs();
+                       return(nil);
+               }
+
+
+       if( strb[0] != NULL_CHAR )      /* if there is something to do */
+       {
+           lispval prev;
+
+           protect(handy = last = newdot()); 
+           strbuf[1] = NULL_CHAR ;     /* set up for getatom */
+           atmlen = 2;
+
+           for(i=0; ch = strb[i++]; ) {
+               switch(kind) {
+
+                 case 0: strbuf[0] = hash = ch;   /* character explode */
+                         last->d.car = (lispval) getatom(TRUE); /* look in oblist */
+                         break;
+
+                 case 1: 
+                         last->d.car = inewint(ch);
+                         break;
+               }
+
+               /* advance pointers */
+               prev = last;
+               last->d.cdr = newdot();
+               last = last->d.cdr;
+           }
+
+           /* end list with a nil pointer */
+           prev->d.cdr = nil;
+           Freexs();
+           Restorestack();
+           return(handy);
+       }
+       Freexs();
+       Restorestack();
+       return(nil);    /* return nil if no characters */
+}
+
+/*===========================
+-
+- (aexplodec 'atm) returns (a t m)
+- (aexplodec 234) returns (\2 \3 \4)
+-===========================*/
+
+lispval
+Lxpldc()
+{ return(Lexpldx(0,0)); }
+
+
+/*===========================
+-
+- (aexploden 'abc) returns (65 66 67)
+- (aexploden 123)  returns (49 50 51)
+-=============================*/
+
+
+lispval
+Lxpldn()
+{ return(Lexpldx(1,0)); }
+
+/*===========================
+-
+- (aexplode "123")  returns (\\ \1 \2 \3);
+- (aexplode 123)  returns (\1 \2 \3);
+-=============================*/
+
+lispval
+Lxplda()
+{ return(Lexpldx(0,1)); }
+
+/*
+ * (argv) returns how many arguments where on the command line which invoked
+ * lisp; (argv i) returns the i'th argument made into an atom;
+ */
+
+lispval
+Largv()
+{
+       register lispval handy;
+       extern int Xargc;
+       extern char **Xargv;
+
+       if(lbot-np==0)handy = nil;
+       else handy = lbot->val;
+       
+       if(TYPE(handy)==INT && handy->i>=0 && handy->i<Xargc) {
+               strcpy(strbuf,Xargv[handy->i]);
+               return(getatom(FALSE));
+       } else { 
+               return(inewint(Xargc));
+       }
+}
+/*
+ * (chdir <atom>) executes a chdir command
+ * if successful, return t otherwise returns nil
+ */
+lispval Lchdir(){
+       register char *filenm;
+
+       chkarg(1,"chdir");
+       filenm = (char *) verify(lbot->val,"chdir - non symbol or string arg");
+       if(chdir(filenm)>=0)
+               return(tatom);
+       else
+               return(nil);
+}
+
+/* ==========================================================
+-
+-      ascii   - convert from number to ascii character
+-
+- form:(ascii number)
+-
+-      the number is checked so that it is in the range 0-255
+- then it is made a character and returned
+- =========================================================*/
+
+lispval
+Lascii() 
+{
+       register lispval handy;
+
+       handy = lbot->val;              /* get argument */
+
+       if(TYPE(handy) != INT)          /* insure that it is an integer */
+       {       error("argument not an integer",FALSE);
+               return(nil);
+       }
+
+       if(handy->i < 0 || handy->i > 0377)     /* insure that it is in range*/
+       {       error("argument is out of ascii range",FALSE);
+               return(nil);
+       }
+
+       strbuf[0] = handy->i ;  /* ok value, make into a char */
+       strbuf[1] = NULL_CHAR;
+
+       /* lookup and possibly intern the atom given in strbuf */
+
+       return( (lispval) getatom(TRUE) );
+}
+
+/*
+ *  boole - maclisp bitwise boolean function
+ *  (boole k x y) where k determines which of 16 possible bitwise 
+ *  truth tables may be applied.  Common values are 1 (and) 6 (xor) 7 (or)
+ *  the result is mapped over each pair of bits on input
+ */
+lispval
+Lboole(){
+       register x, y;
+       register struct argent *mynp;
+       int k;
+
+       if(np - lbot < 3)
+               error("Boole demands at least 3 args",FALSE);
+       mynp = lbot+AD;
+       k = mynp->val->i & 15;
+       x = (mynp+1)->val->i;
+       for(mynp += 2; mynp < np; mynp++) {
+               y = mynp->val->i;
+               switch(k) {
+
+               case 0: x = 0;
+                       break;
+               case 1: x = x & y;
+                       break;
+               case 2: x = y & ~x;
+                       break;
+               case 3: x = y;
+                       break;
+               case 4: x = x & ~y;
+                       break;
+               /* case 5:      x = x; break; */
+               case 6: x = x ^ y;
+                       break;
+               case 7: x = x | y;
+                       break;
+               case 8: x = ~(x | y);
+                       break;
+               case 9: x = ~(x ^ y);
+                       break;
+               case 10: x = ~x;
+                       break;
+               case 11: x = ~x | y;
+                       break;
+               case 12: x = ~y;
+                       break;
+               case 13: x = x | ~y;
+                       break;
+               case 14: x = ~x | ~y;
+                       break;
+               case 15: x = -1;
+               }
+       }
+       return(inewint(x));
+}
+lispval
+Lfact()
+{
+       register lispval result, handy;
+       register itemp;
+       Savestack(3); /* fixup entry mask */
+
+       result = lbot->val;
+       if(TYPE(result)!=INT) error("Factorial of Non-fixnum.  If you want me\
+to calculate fact of > 2^30 We will be here till doomsday!.",FALSE);
+       itemp = result->i;
+       protect(result = newsdot());
+       result->s.CDR=(lispval)0;
+       result->i = 1;
+       for(; itemp > 1; itemp--)
+               dmlad(result,(long)itemp,0L);
+       if(result->s.CDR) 
+       {
+           Restorestack();
+           return(result);
+       }
+       handy = inewint(result->s.I);
+       pruneb(result);
+       Restorestack();
+       return(handy);
+}
+/*
+ * fix -- maclisp floating to fixnum conversion
+ * for the moment, mereley convert floats to ints.
+ * eventual convert to bignum if too big to fit.
+ */
+ lispval Lfix() 
+ {
+       register lispval handy;
+       double floor();
+
+       chkarg(1,"fix");
+       handy = lbot->val;
+       switch(TYPE(handy)) {
+       default:
+               error("innaproriate arg to fix.",FALSE);
+       case INT:
+       case SDOT:
+               return(handy);
+       case DOUB:
+               return(inewint((int)floor(handy->r)));
+       }
+}
+/*
+ * (frexp <real no>)
+ * returns a dotted pair (<exponent>. <bignum>)
+ * such that bignum is 56 bits long, and if you think of the binary
+ * point occuring after the high order bit, <real no> = 2^<exp> * <bignum>
+ *
+ * myfrexp is an assembly language routine found in bigmath.s to do exactly
+ * what is necessary to accomplish this.
+ * this routine is horribly vax specific.
+ *
+ * Lfix should probably be rewritten to take advantage of myfrexp
+ */
+lispval
+Lfrexp()
+{
+       register lispval handy, result;
+       int exp, hi, lo;
+
+       Savestack(2);
+       chkarg(1,"frexp");
+
+       myfrexp(lbot->val->r, &exp, &hi, &lo);
+       if(lo < 0) {
+               /* normalize for bignum */
+               lo &= ~ 0xC0000000;
+               hi += 1;
+       }
+       result = handy = newdot(); 
+       protect(handy);
+       handy->d.car = inewint(exp);
+       if(hi==0&&lo==0) {
+               handy->d.cdr = inewint(0);
+       } else {
+               handy = handy->d.cdr = newsdot();
+               handy->s.I = lo;
+               handy = handy->s.CDR = newdot();
+               handy->s.I = hi;
+               handy->s.CDR = 0;
+       }
+       np--;
+       Restorestack();
+       return(result);
+}
+
+#define SIGFPE 8
+#define B 1073741824.0
+static double table[] = { 1.0, B, B*B, B*B*B, B*B*B*B, 0.0};
+
+lispval
+Lfloat()
+{
+       register lispval handy,result;
+       register double sum = 0;
+       register int count;
+       chkarg(1,"float");
+       handy = lbot->val;
+       switch(TYPE(handy))
+       {
+         case DOUB: return(handy);
+
+
+         case INT:  result = newdoub();
+                    result->r = (double) handy->i;
+                    return(result);
+         case SDOT: 
+         {
+               for(handy = lbot->val, count = 0;
+                   count < 5;
+                   count++, handy = handy->s.CDR) {
+                       sum += handy->s.I * table[count];
+                       if(handy->s.CDR==(lispval)0) goto done;
+               }
+               kill(getpid(),SIGFPE);
+       done:
+               result = newdoub();
+               result->r = sum;
+               return(result);
+       }
+         default: errorh1(Vermisc,"Bad argument to float",nil,FALSE,0,handy);
+         /* NOTREACHED */
+       }
+}
+double
+Ifloat(handy)
+register lispval handy;
+{
+       register double sum = 0.0; register int count=0;
+       for(; count < 5; count++, handy = handy->s.CDR) {
+               sum += handy->s.I * table[count];
+               if(handy->s.CDR==(lispval)0) goto done;
+       }
+       kill(getpid(),SIGFPE);
+       done:
+       return(sum);
+}
+
+/* Lbreak ***************************************************************/
+/* If first argument is not nil, this is evaluated and printed.  Then  */
+/* error is called with the "breaking" message.                                */
+lispval Lbreak() {
+
+       if (np > lbot) {
+               printr(lbot->val,poport);
+               dmpport(poport);
+       }
+       return(error("",TRUE));
+}
+
+
+lispval
+LDivide() {
+       register lispval result, work;
+       register struct argent *mynp;
+       lispval quo, rem, arg1, arg2; struct sdot dummy, dum2;
+       Savestack(3);
+
+       chkarg(2,"Divide");
+       mynp = lbot;
+       work = mynp++->val;
+       switch(TYPE(work)) {
+       case INT:
+               arg1 = (lispval) &dummy;
+               dummy.I = work->i;
+               dummy.CDR = (lispval) 0;
+               break;
+       case SDOT:
+               arg1 = work;
+               break;
+       urk:
+       default:
+               error("First arg to divide neither a bignum nor int.",FALSE);
+       }
+       work = mynp->val;
+       switch(TYPE(work)) {
+       case INT:
+               arg2 = (lispval) &dum2;
+               dum2.I = work->i;
+               dum2.CDR = (lispval) 0;
+               break;
+       case SDOT:
+               arg2 = work;
+               break;
+       default:
+               goto urk;
+       }
+       divbig(arg1,arg2, &quo, &rem);
+       protect(quo);
+       if(rem==((lispval)&dummy))
+               rem = inewint(dummy.I);
+       protect(rem);
+       protect(result = work = newdot());
+       work->d.car = quo;
+       (work->d.cdr = newdot())->d.car = rem;
+       Restorestack();
+       return(result);
+}
+
+lispval LEmuldiv(){
+       register struct argent * mynp = lbot+AD;
+       register lispval work, result;
+       int quo, rem;
+       Savestack(3); /* fix register mask */
+
+       /* (Emuldiv mul1 mult2 add quo) => 
+               temp = mul1 + mul2 + sext(add);
+               result = (list temp/quo temp%quo);
+               to mix C and lisp a bit */
+
+       Imuldiv(mynp[0].val->i, mynp[1].val->i, mynp[2].val->i,
+               mynp[3].val->i, &quo, &rem);
+       protect(result=newdot());
+       (result->d.car=inewint(quo));
+       work = result->d.cdr = newdot();
+       (work->d.car=inewint(rem));
+       Restorestack();
+       return(result);
+}
diff --git a/usr/src/usr.bin/lisp/franz/lam7.c b/usr/src/usr.bin/lisp/franz/lam7.c
new file mode 100644 (file)
index 0000000..1c4a5d4
--- /dev/null
@@ -0,0 +1,638 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: lam7.c,v 1.9 87/12/14 18:48:02 sklower Exp $";
+#endif
+
+/*                                     -[Fri Aug  5 12:51:31 1983 by jkf]-
+ *     lam7.c                          $Locker:  $
+ * lambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#include <signal.h>
+
+
+lispval
+Lfork() {
+       int pid;
+
+       chkarg(0,"fork");
+       if ((pid=fork())) {
+               return(inewint(pid));
+       } else
+               return(nil);
+}
+
+lispval
+Lwait()
+{
+       register lispval ret, temp;
+       int status = -1, pid;
+       Savestack(2);
+
+
+       chkarg(0,"wait");
+       pid = wait(&status);
+       ret = newdot();
+       protect(ret);
+       temp = inewint(pid);
+       ret->d.car = temp;
+       temp = inewint(status);
+       ret->d.cdr = temp;
+       Restorestack();
+       return(ret);
+}
+
+lispval
+Lpipe()
+{
+       register lispval ret, temp;
+       int pipes[2];
+       Savestack(2);
+
+       chkarg(0,"pipe");
+       pipes[0] = -1;
+       pipes[1] = -1;
+       pipe(pipes);
+       ret = newdot();
+       protect(ret);
+       temp = inewint(pipes[0]);
+       ret->d.car = temp;
+       temp = inewint(pipes[1]);
+       ret->d.cdr = temp;
+       Restorestack();
+       return(ret);
+}
+
+lispval
+Lfdopen()
+{
+       register lispval fd, type;
+       FILE *ptr;
+
+       chkarg(2,"fdopen");
+       type = (np-1)->val;
+       fd = lbot->val;
+       if( TYPE(fd)!=INT )
+               return(nil);
+       if ( (ptr=fdopen((int)fd->i, (char *)type->a.pname))==NULL)
+               return(nil);
+       return(P(ptr));
+}
+
+lispval
+Lexece()
+{
+       lispval fname, arglist, envlist, temp;
+       char *args[100], *envs[100], estrs[1024];
+       char *p, *cp, **argsp;
+
+       fname = nil;
+       arglist = nil;
+       envlist = nil;
+
+       switch(np-lbot) {
+       case 3: envlist = lbot[2].val;
+       case 2: arglist = lbot[1].val;
+       case 1: fname   = lbot[0].val;
+       case 0: break;
+       default:
+               argerr("exece");
+       }
+
+       while (TYPE(fname)!=ATOM)
+          fname = error("exece: non atom function name",TRUE);
+       while (TYPE(arglist)!=DTPR && arglist!=nil)
+               arglist = error("exece: non list arglist",TRUE);
+       for (argsp=args; arglist!=nil; arglist=arglist->d.cdr) {
+               temp = arglist->d.car;
+               if (TYPE(temp)!=ATOM)
+                       error("exece: non atom argument seen",FALSE);
+               *argsp++ = temp->a.pname;
+       }
+       *argsp = 0;
+       if (TYPE(envlist)!=DTPR && envlist!=nil)
+               return(nil);
+       for (argsp=envs,cp=estrs; envlist!=nil; envlist=envlist->d.cdr) {
+               temp = envlist->d.car;
+               if (TYPE(temp)!=DTPR || TYPE(temp->d.car)!=ATOM
+                 || TYPE(temp->d.cdr)!=ATOM)
+                    error("exece: Bad enviroment list",FALSE);
+               *argsp++ = cp;
+               for (p=temp->d.car->a.pname; (*cp++ = *p++);) ;
+               *(cp-1) = '=';
+               for (p=temp->d.cdr->a.pname; (*cp++ = *p++);) ;
+       }
+       *argsp = 0;
+       
+       return(inewint(execve(fname->a.pname, args, envs)));
+}
+
+/* Lprocess -
+ * C code to implement the *process function
+ * call:
+ *     (*process 'st_command ['s_readp ['s_writep]])
+ * where st_command is the command to execute
+ *   s_readp is non nil if you want a port to read from returned
+ *   s_writep is non nil if you want a port to write to returned
+ *   both flags default to nil
+ * *process returns
+ *    the exit status of the process if s_readp and s_writep not given
+ *     (in this case the parent waits for the child to finish)
+ *    a list of (readport writeport childpid) if one of s_readp or s_writep
+ *    is given.  If only s_readp is non nil, then writeport will be nil,
+ *    If only s_writep is non nil, then readport will be nil
+ */
+
+lispval
+Lprocess()
+{
+       int wflag , childsi , childso , child;
+       lispval handy;
+       char *command, *p;
+       int writep, readp;
+       int itemp;
+       int (*handler)(), (*signal())();
+       FILE *bufs[2],*obufs[2], *fpipe();
+       Savestack(0);
+
+       writep = readp = FALSE;
+       wflag = TRUE;
+       
+       switch(np-lbot) {
+       case 3:  if(lbot[2].val != nil) writep = TRUE;
+       case 2:  if(lbot[1].val != nil) readp = TRUE;
+                wflag = 0;
+       case 1:  command = (char *) verify(lbot[0].val,
+                                           "*process: non atom first arg");
+                break;
+       default:
+               argerr("*process");
+       }
+       
+       childsi = 0;
+       childso = 1;
+
+       /* if there will be communication between the processes,
+        * it will be through these pipes:
+        *  parent ->  bufs[1] ->  bufs[0] -> child    if writep
+        *  parent <- obufs[0] <- obufs[1] <- parent   if readp
+        */
+       if(writep) {
+           fpipe(bufs);
+           childsi = fileno(bufs[0]);
+       }
+       
+       if(readp) {
+               fpipe(obufs);
+               childso = fileno(obufs[1]);
+       }
+       
+       handler = signal(SIGINT,SIG_IGN);
+       if((child = vfork()) == 0 ) {
+               /* if we will wait for the child to finish
+                * and if the process had ignored interrupts before
+                * we were called, then leave them ignored, else
+                * set it back the the default (death)
+                */
+               if(wflag && handler != SIG_IGN)
+                       signal(2,SIG_DFL);
+                       
+               if(writep) {
+                       close(0);
+                       dup(childsi);
+               }
+               if (readp) {
+                       close(1);
+                       dup(childso);
+               }
+               if ((p = (char *)getenv("SHELL")) != (char *)0) {
+                       execlp(p , p, "-c",command,0);
+                       _exit(-1); /* if exec fails, signal problems*/
+               } else {
+                       execlp("csh", "csh", "-c",command,0);
+                       execlp("sh", "sh", "-c",command,0);
+                       _exit(-1); /* if exec fails, signal problems*/
+               }
+       }
+
+       /* close the duplicated file descriptors
+        * e.g. if writep is true then we've created two desriptors,
+        *  bufs[0] and bufs[1],  we will write to bufs[1] and the
+        *  child (who has a copy of our bufs[0]) will read from bufs[0]
+        *  We (the parent) close bufs[0] since we will not be reading
+        *  from it.
+        */
+       if(writep) fclose(bufs[0]);
+       if(readp) fclose(obufs[1]);
+
+       if(wflag && child!= -1) {
+               int status=0;
+               /* we await the death of the child */
+               while(wait(&status)!=child) {}
+               /* the child has died */
+               signal(2,handler);      /* restore the interrupt handler */
+               itemp = status >> 8;
+               Restorestack();
+               return(inewint(itemp)); /* return its status */
+       }
+       /* we are not waiting for the childs death
+        * build a list containing the write and read ports
+        */
+       protect(handy = newdot());
+       handy->d.cdr = newdot();
+       handy->d.cdr->d.cdr = newdot();
+       if(readp) {
+           handy->d.car = P(obufs[0]);
+           ioname[PN(obufs[0])] = (lispval) inewstr((char *) "from-process");
+       }
+       if(writep) {
+           handy->d.cdr->d.car = P(bufs[1]);
+           ioname[PN(bufs[1])] = (lispval) inewstr((char *) "to-process");
+       }
+       handy->d.cdr->d.cdr->d.car = (lispval) inewint(child);
+       signal(SIGINT,handler);
+       Restorestack();
+       return(handy);
+}
+
+extern int gensymcounter;
+
+lispval
+Lgensym()
+{
+       lispval arg;
+       char leader;
+
+       switch(np-lbot)
+       {
+           case 0: arg = nil;
+                   break;
+           case 1: arg = lbot->val;
+                   break;
+           default: argerr("gensym");
+       }
+       leader = 'g';
+       if (arg != nil && TYPE(arg)==ATOM)
+               leader = arg->a.pname[0];
+       sprintf(strbuf, "%c%05d", leader, gensymcounter++);
+       atmlen = 7;
+       return((lispval)newatom(0));
+}
+
+extern struct types {
+char   *next_free;
+int    space_left,
+       space,
+       type,
+       type_len;                       /*  note type_len is in units of int */
+lispval *items,
+       *pages,
+       *type_name;
+struct heads
+       *first;
+} atom_str ;
+
+lispval
+Lremprop()
+{
+       register struct argent *argp;
+       register lispval pptr, ind, opptr;
+       lispval atm;
+       int disemp = FALSE;
+
+       chkarg(2,"remprop");
+       argp = lbot;
+       ind = argp[1].val;
+       atm = argp->val;
+       switch (TYPE(atm)) {
+       case DTPR:
+               pptr = atm->d.cdr;
+               disemp = TRUE;
+               break;
+       case ATOM:
+               if((lispval)atm==nil)
+                       pptr = nilplist;
+               else
+                       pptr = atm->a.plist;
+               break;
+       default:
+               errorh1(Vermisc, "remprop: Illegal first argument :",
+                      nil, FALSE, 0, atm);
+       }
+       opptr = nil;
+       if (pptr==nil) 
+               return(nil);
+       while(TRUE) {
+               if (TYPE(pptr->d.cdr)!=DTPR)
+                       errorh1(Vermisc, "remprop: Bad property list",
+                              nil, FALSE, 0,atm);
+               if (pptr->d.car == ind) {
+                       if( opptr != nil)
+                               opptr->d.cdr = pptr->d.cdr->d.cdr;
+                       else if(disemp)
+                               atm->d.cdr = pptr->d.cdr->d.cdr;
+                       else if(atm==nil)
+                               nilplist = pptr->d.cdr->d.cdr;
+                       else
+                               atm->a.plist = pptr->d.cdr->d.cdr;
+                       return(pptr->d.cdr);
+               }
+               if ((pptr->d.cdr)->d.cdr == nil) return(nil);
+               opptr = pptr->d.cdr;
+               pptr = (pptr->d.cdr)->d.cdr;
+       }
+}
+
+lispval
+Lbcdad()
+{
+       lispval ret, temp;
+
+       chkarg(1,"bcdad");
+       temp = lbot->val;
+       if (TYPE(temp)!=ATOM)
+               error("ONLY ATOMS HAVE FUNCTION BINDINGS", FALSE);
+       temp = temp->a.fnbnd;
+       if (TYPE(temp)!=BCD)
+               return(nil);
+       ret = newint();
+       ret->i = (int)temp;
+       return(ret);
+}
+
+lispval
+Lstringp()
+{
+       chkarg(1,"stringp");
+       if (TYPE(lbot->val)==STRNG)
+               return(tatom);
+       return(nil);
+}
+
+lispval
+Lsymbolp()
+{
+       chkarg(1,"symbolp");
+       if (TYPE(lbot->val)==ATOM)
+               return(tatom);
+       return(nil);
+}
+
+lispval
+Lrematom()
+{
+       register lispval temp;
+
+       chkarg(1,"rematom");
+       temp = lbot->val;
+       if (TYPE(temp)!=ATOM)
+               return(nil);
+       temp->a.fnbnd = nil;
+       temp->a.pname = (char *)CNIL;
+       temp->a.plist = nil;
+       (atom_items->i)--;
+       (atom_str.space_left)++;
+       temp->a.clb=(lispval)atom_str.next_free;
+       atom_str.next_free=(char *) temp;
+       return(tatom);
+}
+
+#define QUTMASK 0200
+#define VNUM 0000
+
+lispval
+Lprname()
+{
+       lispval a, ret;
+       register lispval work, prev;
+       char    *front, *temp; int clean;
+       char ctemp[100];
+       extern unsigned char *ctable;
+       Savestack(2);
+
+       chkarg(1,"prname");
+       a = lbot->val;
+       switch (TYPE(a)) {
+               case INT:
+                       sprintf(ctemp,"%d",a->i);
+                       break;
+
+               case DOUB:
+                       sprintf(ctemp,"%f",a->r);
+                       break;
+       
+               case ATOM:
+                       temp = front = a->a.pname;
+                       clean = *temp;
+                       if (*temp == '-') temp++;
+                       clean = clean && (ctable[*temp] != VNUM);
+                       while (clean && *temp)
+                               clean = (!(ctable[*temp++] & QUTMASK));
+                       if (clean)
+                               strncpy(ctemp, front, 99);
+                       else    
+                               sprintf(ctemp,"\"%s\"",front);
+                       break;
+       
+               default:
+                       error("prname does not support this type", FALSE);
+       }
+       temp = ctemp;
+       protect(ret = prev = newdot());
+       while (*temp) {
+               prev->d.cdr = work = newdot();
+               strbuf[0] = *temp++;
+               strbuf[1] = 0;
+               work->d.car = getatom(FALSE);
+               work->d.cdr = nil;
+               prev = work;
+       }
+       Restorestack();
+       return(ret->d.cdr);
+}
+
+lispval
+Lexit()
+{
+       register lispval handy;
+       if(np-lbot==0) franzexit(0);
+       handy = lbot->val;
+       if(TYPE(handy)==INT)
+               franzexit((int) handy->i);
+       franzexit(-1);
+}
+lispval
+Iimplode(unintern)
+{
+       register lispval handy, work;
+       register char *cp = strbuf;
+       extern int atmlen;      /* used by newatom and getatom */
+       extern char *atomtoolong();
+
+       chkarg(1,"implode");
+       for(handy = lbot->val; handy!=nil; handy = handy->d.cdr)
+       {
+               work = handy->d.car;
+               if(cp >= endstrb)
+                       cp = atomtoolong(cp);
+       again:
+               switch(TYPE(work))
+               {
+               case ATOM:
+                       *cp++ = work->a.pname[0];
+                       break;
+               case SDOT:
+                       *cp++ = work->s.I;
+                       break;
+               case INT:
+                       *cp++ = work->i;
+                       break;
+               case STRNG:
+                       *cp++ = * (char *) work;
+                       break;
+               default:
+                       work = errorh1(Vermisc,"implode/maknam: Illegal type for this arg:",nil,FALSE,44,work);
+                       goto again;
+               }
+       }
+       *cp = 0;
+       if(unintern) return((lispval)newatom(FALSE));
+       else return((lispval) getatom(FALSE));
+}
+
+lispval
+Lmaknam()
+{
+       return(Iimplode(TRUE));         /* unintern result */
+}
+
+lispval
+Limplode()
+{
+       return(Iimplode(FALSE));        /* intern result */
+}
+
+lispval
+Lntern()
+{
+       register int hash;
+       register lispval handy,atpr;
+
+
+       chkarg(1,"intern");
+       if(TYPE(handy=lbot->val) != ATOM)
+               errorh1(Vermisc,"non atom to intern ",nil,FALSE,0,handy);
+       /* compute hash of pname of arg */
+       hash = hashfcn(handy->a.pname);
+
+       /* search for atom with same pname on hash list */
+
+       atpr = (lispval) hasht[hash];
+       for(atpr = (lispval) hasht[hash] 
+                ; atpr != CNIL 
+                ; atpr = (lispval)atpr->a.hshlnk)
+       {
+               if(strcmp(atpr->a.pname,handy->a.pname) == 0) return(atpr);
+       }
+       
+       /* not there yet, put the given one on */
+
+       handy->a.hshlnk = hasht[hash];
+       hasht[hash] = (struct atom *)handy;
+       return(handy);
+}
+
+/*** Ibindvars :: lambda bind values to variables
+       called with a list of variables and values.
+       does the special binding and returns a fixnum which represents
+       the value of bnp before the binding
+       Use by compiled progv's.
+ ***/
+lispval
+Ibindvars()
+{
+    register lispval vars,vals,handy;
+    struct nament *oldbnp = bnp;
+
+    chkarg(2,"int:bindvars");
+
+    vars = lbot[0].val;
+    vals = lbot[1].val;
+
+    if(vars == nil) return(inewint(oldbnp));
+
+    if(TYPE(vars) != DTPR)
+      errorh1(Vermisc,"progv (int:bindvars): bad first argument ", nil,
+               FALSE,0,vars);
+   if((vals != nil) && (TYPE(vals) != DTPR))
+     errorh1(Vermisc,"progv (int:bindvars): bad second argument ",nil,
+               FALSE,0,vals);
+
+   for( ; vars != nil ; vars = vars->d.cdr , vals=vals->d.cdr)
+   {
+       handy = vars->d.car;
+       if(TYPE(handy) != ATOM)
+          errorh1(Vermisc,"progv (int:bindvars): non symbol argument to bind ",
+               nil,FALSE,0,handy);
+       PUSHDOWN(handy,vals->d.car);
+   }
+   return(inewint(oldbnp));
+}
+
+
+/*** Iunbindvars :: unbind the variable stacked by Ibindvars
+     called by compiled progv's
+ ***/
+lispval
+Iunbindvars()
+{
+    struct nament *oldbnp;
+    
+    chkarg(1,"int:unbindvars");
+    oldbnp = (struct nament *) (lbot[0].val->i);
+    if((oldbnp < orgbnp)  || ( oldbnp > bnp))
+       errorh1(Vermisc,"int:unbindvars: bad bnp value given ",nil,FALSE,0,
+                       lbot[0].val);
+    popnames(oldbnp);
+    return(nil);
+}
+
+/*
+ * (time-string ['x_milliseconds])
+ * if given no argument, returns the current time as a string
+ * if given an argument which is a fixnum representing the current time
+ * as a fixnum, it generates a string from that
+ *
+ * the format of the string returned is that defined in the Unix manual
+ * except the trailing newline is removed.
+ *
+ */
+lispval
+Ltymestr()
+{
+    long timevalue;
+    char *retval;
+    
+    switch(np-lbot)
+    {
+       case 0: time(&timevalue);
+               break;
+       case 1: while (TYPE(lbot[0].val) != INT)
+                 lbot[0].val =
+                    errorh(Vermisc,"time-string: non fixnum argument ",
+                               nil,TRUE,0,lbot[0].val);
+               timevalue = lbot[0].val->i;
+               break;
+       default:
+               argerr("time-string");
+    }
+
+    retval = (char *) ctime(&timevalue);
+    /* remove newline character */
+    retval[strlen(retval)-1] = '\0';
+    return((lispval) inewstr(retval));
+}
diff --git a/usr/src/usr.bin/lisp/franz/lam8.c b/usr/src/usr.bin/lisp/franz/lam8.c
new file mode 100644 (file)
index 0000000..10fa1d0
--- /dev/null
@@ -0,0 +1,1311 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: lam8.c,v 1.17 87/12/14 18:48:09 sklower Exp $";
+#endif
+
+/*                                     -[Thu Sep 29 22:24:10 1983 by jkf]-
+ *     lam8.c                          $Locker:  $
+ * lambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "frame.h"
+
+/* various functions from the c math library */
+double sin(),cos(),asin(),acos(),atan2(),sqrt(), log(), exp();
+extern int current;
+
+lispval Imath(func)
+double (*func)();
+{
+       register lispval handy;
+       register double res;
+       chkarg(1,"Math functions");
+
+       switch(TYPE(handy=lbot->val)) {
+        case INT: res = func((double)handy->i); 
+                  break;
+
+        case DOUB: res = func(handy->r);
+                  break;
+
+        default:  error("Non fixnum or flonum to math function",FALSE);
+       }
+       handy = newdoub();
+       handy->r = res;
+       return(handy);
+}
+lispval Lsin()
+{
+       return(Imath(sin));
+}
+
+lispval Lcos()
+{
+       return(Imath(cos));
+}
+
+lispval Lasin()
+{
+       return(Imath(asin));
+}
+
+lispval Lacos()
+{
+       return(Imath(acos));
+}
+
+lispval Lsqrt()
+{
+       return(Imath(sqrt));
+}
+lispval Lexp()
+{
+       return(Imath(exp));
+}
+
+lispval Llog()
+{
+       return(Imath(log));
+}
+
+/* although we call this atan, it is really atan2 to the c-world,
+   that is, it takes two args
+ */
+lispval Latan()
+{
+       register lispval arg;
+       register double arg1v;
+       register double res;
+       chkarg(2,"arctan");
+
+       switch(TYPE(arg=lbot->val)) {
+
+       case INT:  arg1v = (double) arg->i;
+                  break;
+
+       case DOUB: arg1v = arg->r;
+                  break;
+
+       default:   error("Non fixnum or flonum arg to atan2",FALSE);
+       }
+
+       switch(TYPE(arg = (lbot+1)->val)) {
+
+       case INT: res = atan2(arg1v,(double) arg->i);
+                 break;
+
+       case DOUB: res = atan2(arg1v, arg->r);
+                 break;
+
+       default:  error("Non fixnum or flonum to atan2",FALSE);
+       }
+       arg = newdoub();
+       arg->r = res;
+       return(arg);
+}
+
+/* (random) returns a fixnum in the range -2**30 to 2**30 -1
+   (random fixnum) returns a fixnum in the range 0 to fixnum-1
+ */
+lispval
+Lrandom()
+{
+       register int curval;
+       float pow();
+
+       curval = rand();        /* get numb from 0 to 2**31-1 */
+
+       if(np==lbot) return(inewint(curval-(int)pow((double)2,(double)30)));
+
+       if((TYPE(lbot->val) != INT)
+           || (lbot->val->i <= 0)) errorh1(Vermisc,"random: non fixnum arg:",
+                                                nil, FALSE, 0, lbot->val);
+
+       return(inewint(curval % lbot->val->i )); 
+
+}
+lispval
+Lmakunb()
+{
+       register lispval work;
+
+       chkarg(1,"makunbound");
+       work = lbot->val;
+       if(work==nil || (TYPE(work)!=ATOM))
+               return(work);
+       work->a.clb = CNIL;
+       return(work);
+}
+
+lispval
+Lfseek()
+{
+
+       FILE *f;
+       long offset, whence;
+       lispval retp;
+
+       chkarg(3,"fseek");                      /* Make sure there are three arguments*/
+
+       f = lbot->val->p;               /* Get first argument into f */
+       if (TYPE(lbot->val)!=PORT)      /* Check type of first */
+               error("fseek: First argument must be a port.",FALSE);
+
+       offset = lbot[1].val->i;        /* Get second argument */
+       if (TYPE(lbot[1].val)!=INT)
+               error("fseek: Second argument must be an integer.",FALSE);
+
+       whence = lbot[2].val->i;        /* Get last arg */
+       if (TYPE(lbot[2].val)!=INT)
+               error("fseek: Third argument must be an integer.",FALSE);
+
+       if (fseek(f, offset, (int)whence) == -1)
+               error("fseek: Illegal parameters.",FALSE);
+
+       retp = inewint(ftell(f));
+
+       return((lispval) retp);
+}
+
+/* function hashtabstat  : return list of number of members in  each bucket */
+lispval Lhashst()
+{
+       register lispval handy,cur;
+       register struct atom *pnt;
+       int i,cnt;
+       extern int hashtop;
+       Savestack(3);
+
+       handy = newdot();
+       protect(handy);
+       cur = handy;
+       for(i = 0; i < hashtop; i++)
+       {
+           pnt = hasht[i];
+           for(cnt = 0; pnt != (struct atom *) CNIL ; pnt=pnt->hshlnk , cnt++);
+           cur->d.cdr = newdot();
+           cur = cur->d.cdr;
+           cur->d.car = inewint(cnt);
+       }
+       cur->d.cdr = nil;
+       Restorestack();
+       return(handy->d.cdr);
+}
+
+
+/* Lctcherr
+  this routine should only be called by the unwind protect simulation
+  lisp code
+  It is called after an unwind-protect frame has been entered and
+  evalated and we want to get on with the error or throw
+  We only handle the case where there are 0 to 2 extra arguments to the
+  error call.
+*/
+lispval
+Lctcherr()
+{
+       register lispval handy;
+       lispval type,messg,valret,contuab,uniqid,datum1,datum2;
+
+       chkarg(1,"I-throw-err");
+
+       handy = lbot->val;
+       
+       if(TYPE(handy->d.car) == INT)
+       {       /* continuing a non error (throw,reset, etc) */
+               Inonlocalgo((int)handy->d.car->i,
+                           handy->d.cdr->d.car, 
+                           handy->d.cdr->d.cdr->d.car);
+               /* NOT REACHED */
+       }
+
+       if(handy->d.car != nil)
+       {
+           errorh1(Vermisc,"I-do-throw: first element not fixnum or nil",
+                  nil,FALSE,0,handy);
+       }
+           
+       /* decode the arg list */
+       handy = handy->d.cdr;
+       type = handy->d.car;
+       handy = handy->d.cdr;
+       messg = handy->d.car;
+       handy = handy->d.cdr;
+       valret = handy->d.car;
+       handy = handy->d.cdr;
+       contuab = handy->d.car;
+       handy = handy->d.cdr;
+       uniqid = handy->d.car;
+       handy = handy->d.cdr;
+
+       /* if not extra args */
+       if(handy == nil)
+       {
+         errorh(type,messg->a.pname,valret,(int)contuab->i,(int)uniqid->i);
+       }
+       datum1 = handy->d.car;
+       handy = handy->d.cdr;
+
+       /* if one extra arg */
+       if(handy == nil)
+       {
+         errorh1(type,messg->a.pname,valret,(int)contuab->i,(int)uniqid->i,datum1);
+       }
+
+       /* if two or more extra args, just use first 2 */
+       datum2 = handy->d.car;
+       errorh2(type,messg->a.pname,valret,(int)contuab->i,(int)uniqid->i,datum1,datum2);
+}
+
+/*
+ *     (*makhunk '<fixnum>)
+ *                       <fixnum>
+ * Create a hunk of size 2       . <fixnum> must be between 0 and 6.
+ *
+ */
+
+lispval
+LMakhunk()
+{
+       register int hsize, hcntr;
+       register lispval result;
+
+       chkarg(1,"Makehunk");
+       if (TYPE(lbot->val)==INT)
+       {
+               hsize = lbot->val->i;           /* size of hunk (0-6) */
+               if ((hsize >= 0) && (hsize <= 6))
+               {
+                       result = newhunk(hsize);
+                       hsize = 2 << hsize;     /* size of hunk (2-128) */
+                       for (hcntr = 0; hcntr < hsize; hcntr++)
+                               result->h.hunk[hcntr] = hunkfree;
+               }
+               else
+                       error("*makhunk: Illegal hunk size", FALSE);
+       return(result);
+       }
+       else
+               error("*makhunk: First arg must be an fixnum",FALSE);
+       /* NOTREACHED */
+}
+
+/*
+ *     (cxr '<fixnum> '<hunk>)
+ * Returns the <fixnum>'th element of <hunk>
+ *
+ */
+lispval
+Lcxr()
+{
+       register lispval temp;
+
+       chkarg(2,"cxr");
+       if (TYPE(lbot->val)!=INT)
+               error("cxr: First arg must be a fixnum", FALSE);
+       else
+       {
+               if (! HUNKP(lbot[1].val))
+                       error("cxr: Second arg must be a hunk", FALSE);
+               else
+                       if ( (lbot->val->i >= 0) &&
+                            (lbot->val->i < (2 << HUNKSIZE(lbot[1].val))) )
+                       {
+                               temp = lbot[1].val->h.hunk[lbot->val->i];
+                               if (temp != hunkfree)
+                                       return(temp);
+                               else
+                                       error("cxr: Arg outside of hunk range",
+                                             FALSE);
+                       }
+                       else
+                               error("cxr: Arg outside of hunk range", FALSE);
+       }
+       /* NOTREACHED */
+}
+
+/*
+ *     (rplacx '<fixnum> '<hunk> '<expr>)
+ * Replaces the <fixnum>'th element of <hunk> with <expr>.
+ *
+ */
+lispval
+Lrplcx()
+{
+       lispval *handy;
+       chkarg(3,"rplacx");
+       if (TYPE(lbot->val)!=INT)
+               error("rplacx: First arg must be a fixnum", FALSE);
+       else
+       {
+               if (! HUNKP(lbot[1].val))
+                       error("rplacx: Second arg must be a hunk", FALSE);
+               else
+               {
+                       if ( (lbot->val->i >= 0) &&
+                            (lbot->val->i < (2 << HUNKSIZE(lbot[1].val))) )
+                       {
+                          if (*(handy = &(lbot[1].val->h.hunk[lbot->val->i]))
+                                       != hunkfree)
+                                   *handy  = lbot[2].val;
+                               else
+                                       error("rplacx: Arg outside hunk range", FALSE);
+                       }
+                       else
+                               error("rplacx: Arg outside hunk range", FALSE);
+               }
+       }
+       return(lbot[1].val);
+}
+
+/*
+ *     (*rplacx '<fixnum> '<hunk> '<expr>)
+ * Replaces the <fixnum>'th element of <hunk> with <expr>. This is the
+ * same as (rplacx ...) except with this function you can replace EMPTY's.
+ *
+ */
+lispval
+Lstarrpx()
+{
+       chkarg(3,"*rplacx");
+       if (TYPE(lbot->val)!=INT)
+               error("*rplacx: First arg must be a fixnum", FALSE);
+       else
+       {
+               if (! HUNKP(lbot[1].val))
+                       error("*rplacx: Second arg must be a hunk", FALSE);
+               else
+               {
+                       if ( (lbot->val->i >= 0) &&
+                            (lbot->val->i < (2 << HUNKSIZE(lbot[1].val))) )
+                               lbot[1].val->h.hunk[lbot->val->i] = lbot[2].val;
+                       else
+                               error("*rplacx: Arg outside hunk range", FALSE);
+               }
+       }
+       return(lbot[1].val);
+}
+
+/*
+ *     (hunksize '<hunk>)
+ * Returns the size of <hunk>
+ *
+ */
+lispval
+Lhunksize()
+{
+       register int size,i;
+
+       chkarg(1,"hunksize");
+       if (HUNKP(lbot->val))
+       {
+               size = 2 << HUNKSIZE(lbot->val);
+               for (i = size-1; i >= 0; i--)
+               {
+                       if (lbot->val->h.hunk[i] != hunkfree)
+                       {
+                               size = i + 1;
+                               break;
+                       }
+               }
+               return( inewint(size) );
+       }
+       else
+               error("hunksize: First argument must me a hunk", FALSE);
+                       /* NOTREACHED */
+}
+
+/*
+ * (hunk-to-list 'hunk)        returns a list of the hunk elements
+ */
+lispval
+Lhtol()
+{
+    register lispval handy,retval,last;
+    register int i;
+    int size;
+    Savestack(4);
+
+    chkarg(1,"hunk-to-list");
+    handy = lbot->val;
+    if(!(HUNKP(handy)))
+       errorh1(Vermisc,"hunk-to-list: non hunk argument: ", nil,0,FALSE,
+                       handy);
+    size = 2 << HUNKSIZE(handy);
+    retval = nil;
+    for(i=0 ; i < size ; i++)
+    {
+       if(handy->h.hunk[i] != hunkfree)
+       {
+           if(retval==nil)
+           {
+               protect(retval=newdot());
+               last = retval;
+           }
+           else {
+               last = (last->d.cdr = newdot());
+           }
+           last->d.car = handy->h.hunk[i];
+       }
+       else break;
+    }
+    Restorestack();
+    return(retval);
+}
+           
+/*
+ *     (fileopen  filename mode)
+ * open a file for read, write, or append the arguments can be either
+ * strings or atoms.
+ */
+lispval
+Lfileopen()
+{
+       FILE *port;
+       register lispval name;
+       register lispval mode;
+       register char *namech;
+       register char *modech;
+
+       chkarg(2,"fileopen");
+       name = lbot->val;
+       mode = lbot[1].val;
+
+       namech = (char *) verify(name,"fileopen:args must be atoms or strings");
+       modech = (char *) verify(mode,"fileopen:args must be atoms or strings");
+
+       while (modech[0] != 'r' && modech[0] != 'w' && modech[0] != 'a')
+       {
+               mode = errorh(Vermisc,"Modes are only r, w, a.",nil,TRUE,31);
+               modech = (char *) verify(mode,"fileopen:args must be atoms or strings");
+       }
+
+       while ((port = fopen(namech, modech)) == NULL)
+       {
+           name = errorh1(Vermisc,"Unable to open file.",nil,TRUE,31,name);
+           namech = (char *) verify(name,"fileopen:args must be atoms or strings");
+       }
+           /* xports is a FILE *, cc complains about adding pointers */
+
+       ioname[PN(port)] = (lispval) inewstr(namech);   /* remember name */
+       return(P(port));
+}
+
+/*
+ *     (*invmod '<number> '<modulus>)
+ * This function returns the inverse of  <number>
+ * mod <modulus> in balanced representation
+ * It is used in vaxima as a speed enhancement.
+ */
+
+static lispval
+Ibalmod(invmodp)
+{
+       register long mod_div_2, number, modulus;
+
+       chkarg(2,"*mod");
+       if ((TYPE(lbot->val) == INT) && (TYPE(lbot[1].val) == INT))
+       {
+               modulus = lbot[1].val->i;
+               if(invmodp) number = invmod(lbot->val->i , modulus);
+               else number = lbot->val->i % modulus;
+               mod_div_2 = modulus / 2;
+               if (number < 0)
+               {
+                       if (number < (-mod_div_2))
+                               number += modulus;
+               }
+               else
+               {
+                       if (number > mod_div_2)
+                               number -= modulus;
+               }
+               return( inewint(number) );
+       }
+       else
+               error("*mod: Arguments must be fixnums", FALSE);
+       /* NOTREACHED */
+}
+
+invmod (n,modulus)
+long n , modulus;
+
+{ 
+       long a1,a2,a3,y1,y2,y3,q;
+
+       a1 = modulus; 
+       a2 = n; 
+       y1 = 0; 
+       y2= 1; 
+       goto step3;
+step2: 
+       q = a1 /a2; /*truncated quotient */
+       a3= mmuladd(modulus-a2,q,a1,modulus);
+       y3= mmuladd(modulus-y2,q,y1,modulus);
+       a1 = a2; 
+       a2= a3; 
+       y1=y2; 
+       y2=y3;
+step3: 
+       if (a2==0) error("invmod: inverse of zero divisor",TRUE);
+       else if (a2 != 1) goto step2;
+       else return (y2);
+       /* NOTREACHED */
+}
+
+lispval
+Lstarinvmod()
+{
+       return(Ibalmod(TRUE));
+}
+
+/*
+ *     (*mod '<number> '<modulus>)
+ * This function returns <number> mod <modulus> (for balanced modulus).
+ * It is used in vaxima as a speed enhancement.
+ */
+lispval
+LstarMod()
+{
+       return(Ibalmod(FALSE));
+}
+
+lispval
+Llsh()
+{
+       register struct argent *mylbot = lbot;
+       int val,shift;
+
+       chkarg(2,"lsh");
+       if((TYPE(mylbot->val) != INT) || (TYPE(mylbot[1].val) != INT))
+               errorh2(Vermisc,
+                      "Non ints to lsh",
+                      nil,FALSE,0,mylbot->val,mylbot[1].val);
+       val = mylbot[0].val->i;
+       shift = mylbot[1].val->i;
+       if(shift < -32 || shift > 32)
+         return(inewint(0));
+       if (shift < 0)
+               val = val >> -shift;
+       else
+               val = val << shift;
+       if((val < 0) && (shift < 0))
+       {       /* special case: the vax doesn't have a logical shift
+                  instruction, so we must zero out the ones which
+                  will propogate from the sign position
+               */
+               return(inewint ( val & ~(0x80000000 >> -(shift+1))));
+       }
+       else return( inewint(val));
+}
+
+/* very temporary function to test the validity of the bind stack */
+
+bndchk()
+{  
+       register struct nament *npt;
+       register lispval in2;
+
+       in2 = inewint(200);
+       for(npt=orgbnp; npt < bnp; npt++)
+       {  if((int) npt->atm < (int) in2) abort();
+       }
+}
+
+/*
+ *     formatted printer for lisp data
+ *    use: (cprintf formatstring datum [port])
+ */
+lispval
+Lcprintf()
+{
+    FILE *p;
+    char *fstrng;
+    lispval v;
+    if(np-lbot == 2) protect(nil);     /* write to standard output port */
+    chkarg(3,"cprintf");
+
+    fstrng = (char *)verify(lbot->val,"cprintf: first arg not string or symbol");
+
+    p = okport(lbot[2].val,okport(Vpoport->a.clb,poport));
+
+    switch(TYPE(v=lbot[1].val)) {
+
+       case INT:  fprintf(p,fstrng,v->i);
+                  break;
+
+       case DOUB: fprintf(p,fstrng,v->r);
+                  break;
+
+       case ATOM: fprintf(p,fstrng,v->a.pname);
+                  break;
+
+       case STRNG:fprintf(p,fstrng,v);
+                  break;
+
+       default:   error("cprintf: Illegal second argument",FALSE);
+   };
+
+   return(lbot[1].val);
+}
+
+
+/*
+ * C style sprintf: (sprintf "format" {<arg-list>})
+ *
+ * This function stacks the arguments onto the C stack in reverse
+ * order and then calls sprintf with one argument...This is what the
+ * C compiler does, so it works just fine. The return value is the
+ * string that is the result of the sprintf.
+ */
+lispval
+Lsprintf()
+{
+       register struct argent *argp;
+       register int j;
+       char sbuf[600];                 /* better way? */
+       Keepxs();
+
+       if (np-lbot == 0) {
+               argerr("sprintf");
+       }
+       if (TYPE(lbot->val)==STRNG || TYPE(lbot->val)==INT) {
+               for (argp = np-1; argp >= lbot; argp--) {
+                       switch(TYPE(argp->val)) {
+                         case ATOM:
+                               stack((long)argp->val->a.pname);
+                               break;
+
+                         case DOUB:
+#ifndef SPISFP
+                               stack(argp->val->r);
+#else
+                               {double rr = argp->val->r;
+                               stack(((long *)&rr)[1]);
+                               stack(((long *)&rr)[0]);}
+#endif
+                               break;
+
+                         case INT:
+                               stack(argp->val->i);
+                               break;
+
+                         case STRNG:
+                               stack((long)argp->val);
+                               break;
+
+                         default:
+                               error("sprintf: Bad data type to sprintf",
+                                               FALSE);
+                       }
+               }
+               sprintf(sbuf);
+               for (j = 0; j < np-lbot; j++)
+                       unstack();
+       } else
+               error("sprintf: First arg must be an atom or string", FALSE);
+       Freexs();
+       return ((lispval) inewstr(sbuf));
+}
+
+lispval
+Lprobef()
+{
+       char *name;
+       chkarg(1,"probef");
+
+       name = (char *)verify(lbot->val,"probef: not symbol or string arg ");
+
+       if(access(name,0) == 0) return(tatom);
+       else return(nil);
+}
+
+lispval
+Lsubstring()
+{      register char *name;
+       register lispval index,length;
+       int restofstring = FALSE;
+       int len,ind,reallen;
+
+       switch (np-lbot) 
+       {
+         case 2: restofstring = TRUE;
+                 break;
+
+         case 3: break;
+
+         default: chkarg(3,"substring");
+       }
+
+       name = (char *)verify(lbot[0].val,"substring: not symbol or string arg ");
+
+       while (TYPE(index = lbot[1].val) != INT)
+       {  lbot[1].val = errorh1(Vermisc,"substring: non integer index ",nil,
+                                                   TRUE,0,index);
+       }
+
+       len = strlen(name);
+       ind = index->i;
+
+       if(ind < 0) ind = len+1 + ind;
+
+       if(ind < 1 || ind > len) return(nil);   /*index out of bounds*/
+       if(restofstring) return((lispval)inewstr(name+ind-1));
+
+       while (TYPE(length = lbot[2].val) != INT)
+       { lbot[2].val = errorh1(Vermisc,"substring: not integer length ",nil,
+                                                  TRUE,0,length);
+       }
+
+       if((reallen = length->i ) < 0 || (reallen + ind) > len)
+         return((lispval)inewstr(name+ind-1));
+
+       strncpy(strbuf,name+ind-1,reallen);
+       strbuf[reallen] = '\0';
+       return((lispval)newstr(0));
+}
+
+/*
+ * This is substringn
+ */
+lispval
+Lsstrn()
+{
+       register char *name;
+       register int len,ind,reallen;
+       lispval index,length;
+       int restofstring = FALSE;
+       Savestack(4);
+
+       if((np-lbot) == 2) restofstring = TRUE;
+       else { chkarg(3,"substringn");}
+
+       name = (char *) verify(lbot[0].val,"substringn: non symbol or string arg ");
+
+       while (TYPE(index = lbot[1].val) != INT)
+       {  lbot[1].val = errorh1(Vermisc,"substringn: non integer index ",nil,
+                                                   TRUE,0,index);
+       }
+
+       if(!restofstring)
+       {
+           while (TYPE(length = lbot[2].val) != INT)
+           { lbot[2].val = errorh1(Vermisc,"substringn: not integer length ",
+                                                       nil, TRUE,0,length);
+           }
+           reallen = length->i;
+       }
+       else reallen = -1;
+
+       len = strlen(name);
+       ind = index->i;
+       if(ind < 0) ind = len + 1 + ind;
+       if( ind < 1 || ind > len) return(nil);
+
+       if(reallen == 0) 
+           return((lispval)inewint(*(name + ind - 1)));
+       else {
+           char *pnt = name + ind - 1;
+           char *last = name + len -1;
+           lispval cur,start;
+
+           protect(cur = start = newdot());
+           cur->d.car = inewint(*pnt);
+           while(++pnt <= last && --reallen != 0)
+           {
+              cur->d.cdr = newdot();
+              cur = cur->d.cdr;
+              cur->d.car = inewint(*pnt);
+           }
+           Restorestack();
+           return(start);
+       }
+
+}
+
+
+/*
+ * (character-index 'string 'char)
+ * return the index of char in the string.
+ * return nil if not present
+ * char can be a fixnum (representing a character)
+ *  a symbol or string (in which case the first char is used)
+ *
+ */
+
+#if os_unix_ts
+#define index strchr
+#endif
+lispval
+Lcharindex()
+{
+    register char *string;
+    register char ch;
+    char *str2;
+    
+    chkarg(2,"character-index");
+    
+
+    string = (char *)verify(lbot[0].val,"character-index: non symbol or string arg ");
+    if(TYPE(lbot[1].val) == INT)
+       ch = (char) lbot[1].val->i;
+    else {
+       str2 = (char *) verify(lbot[1].val,"character-index: bad first argument ");
+       ch = *str2;     /* grab the first character */
+    }
+    
+    if((str2 = (char *) index(string,ch)) ==  0) return(nil); /* not there */
+    /* return 1-based index of character */
+    return(inewint(str2-string+1));
+}
+    
+        
+lispval Ipurcopy();
+
+
+lispval
+Lpurcopy()
+{
+       chkarg(1,"purcopy");
+       return(Ipurcopy(lbot[0].val));
+}
+           
+lispval
+Ipurcopy(handy)
+lispval handy;
+{
+    extern int *beginsweep;
+    register lispval retv, curv, lv;
+    int i,size;
+
+    switch(TYPE(handy)) {
+
+       case DTPR:
+                  retv = curv = pnewdot();
+                  lv = handy;
+                  while(TRUE)
+                  {
+                     curv->d.car = Ipurcopy(lv->d.car);
+                     if(TYPE(lv = lv->d.cdr) == DTPR)
+                     {
+                         curv->d.cdr = pnewdot();
+                         curv = curv->d.cdr;
+                     }
+                     else {
+                         curv->d.cdr = Ipurcopy(lv);
+                         break;
+                     }
+                   }
+                   return(retv);
+
+       case SDOT:
+                   retv = curv = pnewsdot();
+                   lv = handy;
+                   while(TRUE)
+                   {
+                       curv->s.I = lv->s.I;
+                       if(lv->s.CDR == (lispval) 0) break;
+                       lv = lv->s.CDR;
+                       curv->s.CDR = pnewdot();
+                       curv = curv->s.CDR;
+                   }
+                   curv->s.CDR = 0;
+                   return(retv);
+
+       case INT:
+                   if((int *)handy < beginsweep) return(handy);
+                   retv = pnewint();
+                   retv->i = handy->i;
+                   return(retv);
+
+       case DOUB:
+                   retv = pnewdb();
+                   retv->r = handy->r;
+                   return(retv);
+
+       case HUNK2:
+               i = 0;
+               goto hunkit;
+
+       case HUNK4:
+               i = 1;
+               goto hunkit;
+
+       case HUNK8:
+               i = 2;
+               goto hunkit;
+
+       case HUNK16:
+               i = 3;
+               goto hunkit;
+
+       case HUNK32:
+               i = 4;
+               goto hunkit;
+
+       case HUNK64:
+               i = 5;
+               goto hunkit;
+
+       case HUNK128:
+               i = 6; 
+
+           hunkit:
+               retv = pnewhunk(i);
+               size = 2 << i ; /* number of elements to copy over */
+               for( i = 0; i < size ; i++)
+               {
+                   retv->h.hunk[i] = Ipurcopy(handy->h.hunk[i]);
+               }
+               return(retv);
+
+
+
+       case STRNG:
+#ifdef GCSTRINGS
+               { extern char purepage[];
+
+                 if(purepage[((int)handy)>>9]==0)
+                       return((lispval)pinewstr((char *)handy));}
+               
+#endif
+       case ATOM: 
+       case BCD:
+       case PORT:
+           return(handy);      /* We don't want to purcopy these, yet
+                                * it won't hurt if we don't mark them
+                                * since they either aren't swept or 
+                                * will be marked in a special way 
+                                */
+       case ARRAY:
+               error("purcopy: can't purcopy array structures",FALSE);
+
+       default:
+               error(" bad type to purcopy ",FALSE);
+       /* NOTREACHED */
+    }
+}
+
+/*
+ * Lpurep returns t if the given arg is in pure space
+ */
+lispval
+Lpurep()
+{
+    lispval Ipurep();
+
+    chkarg(1,"purep");
+    return(Ipurep(lbot->val));
+}
+
+
+
+/* vector functions */
+lispval newvec(), nveci(), Inewvector();
+
+/* vector creation and initialization functions */
+lispval
+Lnvec()
+{
+    return(Inewvector(3));
+}
+
+lispval
+Lnvecb()
+{
+    return(Inewvector(0));
+}
+
+lispval
+Lnvecw()
+{
+    return(Inewvector(1));
+}
+
+lispval
+Lnvecl()
+{
+    return(Inewvector(2));
+}
+
+/*
+ * (new-vector 'x_size ['g_fill] ['g_prop])
+ * class = 0: byte \
+ *       = 1: word  > immediate
+ *       = 2: long /
+ *      = 3: long
+ */
+lispval
+Inewvector(class)
+{
+    register int i;
+    register lispval handy;
+    register lispval *handy2;
+    char *chandy;
+    short *whandy;
+    long *lhandy;
+    lispval sizearg, fillarg, proparg;
+    int size, vsize;
+
+    fillarg = proparg = nil;
+    
+    switch(np-lbot) {
+       case 3: proparg = lbot[2].val;
+       case 2: fillarg = lbot[1].val;
+       case 1: sizearg = lbot[0].val;
+               break;
+       default: argerr("new-vector");
+    }
+    
+    while((TYPE(sizearg) != INT) || sizearg->i < 0)
+       sizearg = errorh1(Vermisc,"new-vector: bad size for vector ",nil,
+                               TRUE,0,sizearg);
+    size = sizearg->i;
+    switch(class)
+    {
+       case 0: vsize = size * sizeof(char);
+               break;
+       case 1: vsize = size * sizeof(short);
+               break;
+       default: vsize = size * sizeof(long);
+               break;
+    }
+    
+    if(class != 3) handy = nveci(vsize);
+    else handy = newvec(vsize);
+    
+    switch(class)
+    {
+       case 0: chandy = (char *)handy;
+               for(i = 0 ; i < size ; i++) *chandy++ = (char) (fillarg->i);
+               break;
+               
+       case 1: whandy = (short *)handy;
+               for(i = 0 ; i < size ; i++) *whandy++ = (short) (fillarg->i);
+               break;
+               
+       case 2: lhandy = (long *)handy;
+               for(i = 0 ; i < size ; i++) *lhandy++ = (fillarg->i);
+               break;
+
+       case 3: handy2 = (lispval *)handy;
+               for(i = 0 ; i < size ; i++) *handy2++ = fillarg;
+               break;
+    }
+    handy->v.vector[-1] = proparg;
+    return(handy);
+}
+
+lispval
+Lvectorp()
+{
+    chkarg(1,"vectorp");
+    if(TYPE(lbot->val) == VECTOR) return(tatom);
+    else return(nil);
+}
+
+lispval
+Lpvp()
+{
+    chkarg(1,"vectorip");
+    if(TYPE(lbot->val) == VECTORI) return(tatom);
+    else return(nil);
+}
+
+/*
+ * int:vref  vector[i] index class
+ *  class = 0: byte immed, 1: word immed, 2: long immed, 3: long
+ *
+ * also do C style dereferencing of pointers.  This is a temporary
+ * hack until we decide if we can live without it:
+ *  class = 4: char, 5: short, 6: long, 7: float, 8: double
+ */
+lispval
+LIvref()
+{
+    register lispval vect;
+    register int index;
+    int class;
+    double value;
+    
+    chkarg(3,"int:vref");
+    vect = lbot[0].val;
+    index = lbot[1].val->i;
+    class = lbot[2].val->i;
+    switch(class)
+    {
+        case 0: return(inewint(vect->vb.vectorb[index]));
+        case 1: return(inewint(vect->vw.vectorw[index]));
+        case 2: return(inewint(vect->vl.vectorl[index]));
+       case 3: return(vect->v.vector[index]);
+       case 4: return(inewint(*(char *)(vect->i+index)));
+       case 5: return(inewint(*(short *)(vect->i+index)));
+       case 6: return(inewint(*(long *)(vect->i+index)));
+       case 7: value = *(float *) (vect->i+index);
+               vect = newdoub();
+               vect->r = value;
+               return(vect);
+       case 8: value = *(double *) (vect->i+index);
+               vect = newdoub();
+               vect->r = value;
+               return(vect);
+    }
+    error("int:vref: impossible class detected",FALSE);
+    /* NOTREACHED */
+}
+
+/*
+ * int:vset vector[i] index value class
+ *  class = 0: byte immed, 1: word immed, 2: long immed, 3: long
+ */
+lispval
+LIvset()
+{
+    register lispval vect,value;
+    register int index;
+    int class;
+    
+    chkarg(4,"int:vset");
+    vect = lbot[0].val;
+    index = lbot[1].val->i;
+    value = lbot[2].val;
+    class = lbot[3].val->i;
+    switch(class)
+    {
+        case 0: vect->vb.vectorb[index] = (char)value->i;
+               break;
+        case 1: vect->vw.vectorw[index] = (short)value->i;
+               break;
+        case 2: vect->vl.vectorl[index] = value->i;
+               break;
+       case 3: vect->v.vector[index] = value;
+               break;
+       case 4: *(char *) (vect->i+index) = value->i;
+               break;
+       case 5: *(short *) (vect->i+index) = value->i;
+               break;
+       case 6: *(long *) (vect->i+index) = value->i;
+               break;
+       case 7: *(float *) (vect->i+index) = value->r;
+               break;
+       case 8: *(double *) (vect->i+index) = value->r;
+               break;
+       default:
+       error("int:vref: impossible class detected",FALSE);
+    }
+    return(value);
+}
+
+/*
+ * LIvsize == (int:vsize 'vector 'x_shift)
+ *  return the vsize field of the vector shifted right by x_shift
+ */
+lispval
+LIvsize()
+{
+    int typ;
+    
+    chkarg(2,"int:vsize");
+    return(inewint((lbot[0].val->vl.vectorl[VSizeOff]) >> lbot[1].val->i));
+}
+
+lispval
+Lvprop()
+{
+    int typ;
+    chkarg(1,"vprop");
+    
+    if(((typ = TYPE(lbot->val)) != VECTOR) && (typ != VECTORI))
+       errorh1(Vermisc,"vprop: non vector argument: ", nil, FALSE,0,
+                       lbot->val);
+    return(lbot[0].val->v.vector[VPropOff]);
+}
+
+    
+lispval
+Lvsp()
+{
+       int typ;
+       lispval vector, property;
+       chkarg(2,"vsetprop");
+
+       vector = lbot->val;
+       property = lbot[1].val;
+       typ = TYPE(vector);
+
+       if(typ != VECTOR && typ !=VECTORI)
+               errorh1(Vermisc,"vsetprop: non vector argument: ",
+                               nil,FALSE,0,vector);
+       vector->v.vector[VPropOff] = property;
+       return(property);
+}
+
+
+/* vecequal
+ *  check if the two vector arguments are 'equal'
+ *  this is called by equal which has already checked that
+ *  the arguments are vector
+ */
+vecequal(v,w)
+lispval v,w;
+{
+    int i;
+    lispval vv, ww, ret;
+    int vsize = (int) v->v.vector[VSizeOff];
+    int wsize = (int) w->v.vector[VSizeOff];
+    struct argent *oldlbot = lbot;
+    lispval Lequal();
+
+    if(vsize != wsize) return(FALSE);
+
+    vsize /= sizeof(int);      /* determine number of entries */
+
+    for(i = 0 ; i < vsize ; i++)
+    {
+       vv = v->v.vector[i];
+       ww = w->v.vector[i];
+       /* avoid calling equal if they are eq */
+       if(vv != ww)
+       {
+           lbot = np;
+           protect(vv);
+           protect(ww);
+           ret = Lequal();
+           np = lbot;
+           lbot = oldlbot;
+           if(ret == nil)  return(FALSE);
+       }
+    }
+    return(TRUE);
+}
+            
+/* veciequal
+ *  check if the two vectori arguments are 'equal'
+ *  this is called by equal which has already checked that
+ *  the arguments are vector
+ *  Note: this would run faster if we did as many 'longword'
+ *  comparisons as possible and then did byte comparisons.
+ *  or if we used pointers instead of indexing.
+ */
+veciequal(v,w)
+lispval v,w;
+{
+    char vv, ww;
+    int i;
+    int vsize = (int) v->v.vector[VSizeOff];
+    int wsize = (int) w->v.vector[VSizeOff];
+
+    if(vsize != wsize) return(FALSE);
+
+
+    for(i = 0 ; i < vsize ; i++)
+    {
+       if(v->vb.vectorb[i] != w->vb.vectorb[i]) return(FALSE);
+    }
+    return(TRUE);
+}