Applications/V7: Add the first batch of ANSIfied V7 apps
authorAlan Cox <alan@linux.intel.com>
Wed, 18 Mar 2015 22:52:18 +0000 (22:52 +0000)
committerAlan Cox <alan@linux.intel.com>
Wed, 18 Mar 2015 22:52:18 +0000 (22:52 +0000)
Also add the need BSD style copyright on them

26 files changed:
Applications/V7/COPYRIGHT [new file with mode: 0644]
Applications/V7/cmd/ac.c [new file with mode: 0644]
Applications/V7/cmd/accton.c [new file with mode: 0644]
Applications/V7/cmd/at.c [new file with mode: 0644]
Applications/V7/cmd/atrun.c [new file with mode: 0644]
Applications/V7/cmd/col.c [new file with mode: 0644]
Applications/V7/cmd/comm.c [new file with mode: 0644]
Applications/V7/cmd/cron.c [new file with mode: 0644]
Applications/V7/cmd/crypt.c [new file with mode: 0644]
Applications/V7/cmd/dc.c [new file with mode: 0644]
Applications/V7/cmd/dd.c [new file with mode: 0644]
Applications/V7/cmd/deroff.c [new file with mode: 0644]
Applications/V7/cmd/diff.c [new file with mode: 0644]
Applications/V7/cmd/diff3.c [new file with mode: 0644]
Applications/V7/cmd/diffh.c [new file with mode: 0644]
Applications/V7/cmd/join.c [new file with mode: 0644]
Applications/V7/cmd/look.c [new file with mode: 0644]
Applications/V7/cmd/makekey.c [new file with mode: 0644]
Applications/V7/cmd/mesg.c [new file with mode: 0644]
Applications/V7/cmd/newgrp.c [new file with mode: 0644]
Applications/V7/cmd/pr.c [new file with mode: 0644]
Applications/V7/cmd/ptx.c [new file with mode: 0644]
Applications/V7/games/arithmetic.c [new file with mode: 0644]
Applications/V7/games/backgammon.c [new file with mode: 0644]
Applications/V7/games/fish.c [new file with mode: 0644]
Applications/V7/games/wump.c [new file with mode: 0644]

diff --git a/Applications/V7/COPYRIGHT b/Applications/V7/COPYRIGHT
new file mode 100644 (file)
index 0000000..8bc1f98
--- /dev/null
@@ -0,0 +1,146 @@
+[COPYRIGHT file: V7/x86 distribution]
+
+
+The following copyright notice applies to the UNIX Version 7 and
+32V UNIX portions of this distribution:
+
+Copyright (C) Caldera International Inc. 2001-2002.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+Redistributions of source code and documentation must retain the
+above copyright notice, this list of conditions and the following
+disclaimer.  Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+All advertising materials mentioning features or use of this software
+must display the following acknowledgement:
+
+This product includes software developed or owned by Caldera
+International, Inc.
+
+Neither the name of Caldera International, Inc. nor the names of
+other contributors may be used to endorse or promote products derived
+from this software without specific prior written permission.
+
+USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENCE BY CALDERA
+INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+The following copyright notice applies to the Amsterdam Compiler
+Kit portions of this distribution:
+
+Copyright (c) 1987,1990, 1993 Vrije Universiteit, Amsterdam, The Netherlands.
+All rights reserved.
+
+Redistribution and use of the Amsterdam Compiler Kit in source and
+binary forms, with or without modification, are permitted provided
+that the following conditions are met:
+
+   * Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+
+   * Redistributions in binary form must reproduce the above
+     copyright notice, this list of conditions and the following
+     disclaimer in the documentation and/or other materials provided
+     with the distribution.
+
+   * Neither the name of Vrije Universiteit nor the names of the
+     software authors or contributors may be used to endorse or
+     promote products derived from this software without specific
+     prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
+CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL VRIJE UNIVERSITEIT OR ANY AUTHORS OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+The following copyright notice applies to the Berkeley Software
+Distribution portions of this distribution:
+
+Copyright (c) 1979, 1980 The Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+This product includes software developed by the University of
+California, Berkeley and its contributors.
+4. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+
+Modifications, enhancements, and additions to the supplied software
+are by Robert Nordier, and the following copyright notice applies to
+such modifications, enhancements, and additions, and to the overall
+V7/x86 distribution:
+
+Copyright (c) 1999-2007 Robert Nordier.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/Applications/V7/cmd/ac.c b/Applications/V7/cmd/ac.c
new file mode 100644 (file)
index 0000000..0cfb535
--- /dev/null
@@ -0,0 +1,263 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied and defloated for FUZIX */
+
+/*
+ * acct [ -w wtmp ] [ -d ] [ -p ] [ people ]
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+#include <utmp.h>
+#include <sys/types.h>
+
+#define        TSIZE   33
+#define        USIZE   200
+struct utmp ibuf;
+
+struct ubuf {
+       char uname[8];
+       long utime;
+} ubuf[USIZE];
+
+struct tbuf {
+       struct ubuf *userp;
+       long ttime;
+} tbuf[TSIZE];
+
+const char *wtmp;
+int pflag, byday;
+long dtime;
+time_t midnight;
+long lastime;
+int pcount;
+char **pptr;
+
+const long day = 86400L;
+const long dayandahalf = 86400L + 86400L / 2;
+
+
+void update(struct tbuf *tp, int f)
+{
+       int j;
+       struct ubuf *up;
+       long t, t1;
+
+       if (f)
+               t = midnight;
+       else
+               t = ibuf.ut_time;
+       if (tp->userp) {
+               t1 = t - tp->ttime;
+               if (t1 > 0 && t1 < dayandahalf)
+                       tp->userp->utime += t1;
+       }
+       tp->ttime = t;
+       if (f)
+               return;
+       if (ibuf.ut_user[0] == '\0') {
+               tp->userp = 0;
+               return;
+       }
+       for (up = ubuf; up < &ubuf[USIZE]; up++) {
+               if (up->uname[0] == '\0')
+                       break;
+               for (j = 0; j < 8 && up->uname[j] == ibuf.ut_user[j]; j++);
+               if (j >= 8)
+                       break;
+       }
+       for (j = 0; j < 8; j++)
+               up->uname[j] = ibuf.ut_user[j];
+       tp->userp = up;
+}
+
+int among(int i)
+{
+       register int j, k;
+       register char *p;
+
+       if (pcount == 0)
+               return (1);
+       for (j = 0; j < pcount; j++) {
+               p = pptr[j];
+               for (k = 0; k < 8; k++) {
+                       if (*p == ubuf[i].uname[k]) {
+                               if (*p++ == '\0')
+                                       return (1);
+                       } else
+                               break;
+               }
+       }
+       return (0);
+}
+
+void newday(void)
+{
+#if 0
+       time_t ttime;
+       struct timeb tb;
+
+       time(&ttime);
+/* FIXME: do modern style TZ */
+       if (midnight == 0) {
+               midnight = 60 * (long) tb.timezone;
+               if (localtime(&ttime)->tm_isdst)
+                       midnight -= 3600;
+       }
+/* END */
+#endif
+       while (midnight <= ibuf.ut_time)
+               midnight += day;
+}
+
+void pdate(void)
+{
+       time_t x;
+
+       if (byday == 0)
+               return;
+       x = midnight - 1;
+       printf("%.6s", ctime(&x) + 4);
+}
+
+void printdeci2(long v, int div)
+{
+       int r = ((int) (v / div)) % 100;
+       if (r)
+               printf(".%02d", r);
+}
+
+void print(void)
+{
+       int i;
+       long ttime, t;
+
+       ttime = 0;
+       for (i = 0; i < USIZE; i++) {
+               if (!among(i))
+                       continue;
+               t = ubuf[i].utime;
+               if (t > 0)
+                       ttime += t;
+               if (pflag && ubuf[i].utime > 0) {
+                       printf("\t%-8.8s%6ld\n",
+                              ubuf[i].uname, ubuf[i].utime / 3600L);
+                       printdeci2(ubuf[i].utime, 36);
+               }
+       }
+       if (ttime > 0) {
+               pdate();
+               printf("\ttotal%9ld\n", ttime / 3600L);
+               printdeci2(ttime, 36);
+       }
+}
+
+void upall(int f)
+{
+       register struct tbuf *tp;
+
+       for (tp = tbuf; tp < &tbuf[TSIZE]; tp++)
+               update(tp, f);
+}
+
+void loop(void)
+{
+       register int i;
+       register struct tbuf *tp;
+       register struct ubuf *up;
+
+       if (ibuf.ut_line[0] == '|') {
+               dtime = ibuf.ut_time;
+               return;
+       }
+       if (ibuf.ut_line[0] == '}') {
+               if (dtime == 0)
+                       return;
+               for (tp = tbuf; tp < &tbuf[TSIZE]; tp++)
+                       tp->ttime += ibuf.ut_time - dtime;
+               dtime = 0;
+               return;
+       }
+       if (lastime > ibuf.ut_time || lastime + dayandahalf < ibuf.ut_time)
+               midnight = 0;
+       if (midnight == 0)
+               newday();
+       lastime = ibuf.ut_time;
+       if (byday && ibuf.ut_time > midnight) {
+               upall(1);
+               print();
+               newday();
+               for (up = ubuf; up < &ubuf[USIZE]; up++)
+                       up->utime = 0;
+       }
+       if (ibuf.ut_line[0] == '~') {
+               ibuf.ut_user[0] = '\0';
+               upall(0);
+               return;
+       }
+       if (ibuf.ut_line[0] == 't')
+               i = (ibuf.ut_line[3] - '0') * 10 + (ibuf.ut_line[4] - '0');
+       else
+               i = TSIZE - 1;
+       if (i < 0 || i >= TSIZE)
+               i = TSIZE - 1;
+       tp = &tbuf[i];
+       update(tp, 0);
+}
+
+int main(int argc, char *argv[])
+{
+       int c, fl;
+       register int i;
+       FILE *wf;
+
+       wtmp = "/usr/adm/wtmp";
+       while (--argc > 0 && **++argv == '-')
+               switch (*++*argv) {
+               case 'd':
+                       byday++;
+                       continue;
+
+               case 'w':
+                       if (--argc > 0)
+                               wtmp = *++argv;
+                       continue;
+
+               case 'p':
+                       pflag++;
+                       continue;
+               }
+       pcount = argc;
+       pptr = argv;
+       if ((wf = fopen(wtmp, "r")) == NULL) {
+               printf("No %s\n", wtmp);
+               exit(1);
+       }
+       for (;;) {
+               if (fread((char *) &ibuf, sizeof(ibuf), 1, wf) != 1)
+                       break;
+               fl = 0;
+               for (i = 0; i < 8; i++) {
+                       c = ibuf.ut_user[i];
+                       if (isdigit(c) || isalpha(c)) {
+                               if (fl)
+                                       goto skip;
+                               continue;
+                       }
+                       if (c == ' ' || c == '\0') {
+                               fl++;
+                               ibuf.ut_user[i] = '\0';
+                       } else
+                               goto skip;
+               }
+               loop();
+             skip:;
+       }
+       ibuf.ut_user[0] = '\0';
+       ibuf.ut_line[0] = '~';
+       time(&ibuf.ut_time);
+       loop();
+       print();
+       exit(0);
+}
diff --git a/Applications/V7/cmd/accton.c b/Applications/V7/cmd/accton.c
new file mode 100644 (file)
index 0000000..34af3ea
--- /dev/null
@@ -0,0 +1,19 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int argc, const char *argv[])
+{
+       if (argc > 1)
+               acct(argv[1]);
+       else
+               acct((char *)0);
+       if (errno) {
+               perror("accton");
+               exit(1);
+       }
+       exit(0);
+}
diff --git a/Applications/V7/cmd/at.c b/Applications/V7/cmd/at.c
new file mode 100644 (file)
index 0000000..0128c15
--- /dev/null
@@ -0,0 +1,303 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+/*
+ * at time mon day
+ * at time wday
+ * at time wday 'week'
+ *
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define HOUR 100
+#define HALFDAY        (12*HOUR)
+#define DAY    (24*HOUR)
+#define THISDAY "/usr/spool/at"
+
+const char *days[] = {
+       "sunday",
+       "monday",
+       "tuesday",
+       "wednesday",
+       "thursday",
+       "friday",
+       "saturday",
+};
+
+struct monstr {
+       const char *mname;
+       int mlen;
+} months[] = {
+       {
+       "january", 31}, {
+       "february", 28}, {
+       "march", 31}, {
+       "april", 30}, {
+       "may", 31}, {
+       "june", 30}, {
+       "july", 31}, {
+       "august", 31}, {
+       "september", 30}, {
+       "october", 31}, {
+       "november", 30}, {
+       "december", 31}, {
+0, 0},};
+
+char fname[100];
+int utimev;                    /* requested time in grains */
+int now;                       /* when is it */
+int uday;                      /* day of year to be done */
+int uyear;                     /* year */
+int today;                     /* day of year today */
+FILE *file;
+FILE *ifile;
+
+void onintr(int sig)
+{
+       unlink(fname);
+       exit(1);
+}
+
+char *prefix(char *begin, char *full)
+{
+       int c;
+       while (c = *begin++) {
+               if (isupper(c))
+                       c = tolower(c);
+               if (*full != c)
+                       return (0);
+               else
+                       full++;
+       }
+       return (full);
+}
+
+int makeutime(char *pp)
+{
+       register int val;
+       register char *p;
+
+       /* p points to a user time */
+       p = pp;
+       val = 0;
+       while (isdigit(*p)) {
+               val = val * 10 + (*p++ - '0');
+       }
+       if (p - pp < 3)
+               val *= HOUR;
+
+       for (;;) {
+               switch (*p) {
+
+               case ':':
+                       ++p;
+                       if (isdigit(*p)) {
+                               if (isdigit(p[1])) {
+                                       val += (10 * *p + p[1] - 11 * '0');
+                                       p += 2;
+                                       continue;
+                               }
+                       }
+                       fprintf(stderr, "at: bad time format:\n");
+                       exit(1);
+
+               case 'A':
+               case 'a':
+                       if (val >= HALFDAY + HOUR)
+                               val = DAY + 1;  /* illegal */
+                       if (val >= HALFDAY && val < (HALFDAY + HOUR))
+                               val -= HALFDAY;
+                       break;
+
+               case 'P':
+               case 'p':
+                       if (val >= HALFDAY + HOUR)
+                               val = DAY + 1;  /* illegal */
+                       if (val < HALFDAY)
+                               val += HALFDAY;
+                       break;
+
+               case 'n':
+               case 'N':
+                       val = HALFDAY;
+                       break;
+
+               case 'M':
+               case 'm':
+                       val = 0;
+                       break;
+
+
+               case '\0':
+               case ' ':
+                       /* 24 hour time */
+                       if (val == DAY)
+                               val -= DAY;
+                       break;
+
+               default:
+                       fprintf(stderr, "at: bad time format\n");
+                       exit(1);
+
+               }
+               break;
+       }
+       if (val < 0 || val >= DAY) {
+               fprintf(stderr, "at: time out of range\n");
+               exit(1);
+       }
+       if (val % HOUR >= 60) {
+               fprintf(stderr, "at: illegal minute field\n");
+               exit(1);
+       }
+       utimev = val;
+}
+
+
+int makeuday(int argc, const char *argv[])
+{
+       /* the presumption is that argv[2], argv[3] are either
+          month day OR weekday [week].  Returns either 2 or 3 as last
+          argument used */
+       /* first of all, what's today */
+       time_t tm;
+       int found = -1;
+       char **ps;
+       struct tm *detail;
+       struct monstr *pt;
+
+       time(&tm);
+       detail = localtime(&tm);
+       uday = today = detail->tm_yday;
+       uyear = detail->tm_year;
+       now = detail->tm_hour * 100 + detail->tm_min;
+       if (argc <= 2)
+               return (1);
+       /* is the next argument a month name ? */
+       for (pt = months; pt->mname; pt++) {
+               if (prefix(argv[2], pt->mname)) {
+                       if (found < 0)
+                               found = pt - months;
+                       else {
+                               fprintf(stderr, "at: ambiguous month\n");
+                               exit(1);
+                       }
+               }
+       }
+       if (found >= 0) {
+               if (argc <= 3)
+                       return (2);
+               uday = atoi(argv[3]) - 1;
+               if (uday < 0) {
+                       fprintf(stderr, "at: illegal day\n");
+                       exit(1);
+               }
+               while (--found >= 0)
+                       uday += months[found].mlen;
+               if (detail->tm_year % 4 == 0 && uday > 59)
+                       uday += 1;
+               return (3);
+       }
+       /* not a month, try day of week */
+       found = -1;
+       for (ps = days; ps < days + 7; ps++) {
+               if (prefix(argv[2], *ps)) {
+                       if (found < 0)
+                               found = ps - days;
+                       else {
+                               fprintf(stderr,
+                                       "at: ambiguous day of week\n");
+                               exit(1);
+                       }
+               }
+       }
+       if (found < 0)
+               return (1);
+       /* find next day of this sort */
+       uday = found - detail->tm_wday;
+       if (uday <= 0)
+               uday += 7;
+       uday += today;
+       if (argc > 3 && strcmp("week", argv[3]) == 0) {
+               uday += 7;
+               return (3);
+       }
+       return (2);
+}
+
+
+void filename(char *dir, int y, int d, int t)
+{
+       register int i;
+
+       for (i = 0;; i += 53) {
+               sprintf(fname, "%s/%02d.%03d.%04d.%02d", dir, y, d, t,
+                       (getpid() + i) % 100);
+               if (access(fname, 0) == -1)
+                       return;
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       register int c;
+       char pwbuf[100];
+       FILE *pwfil;
+       int larg;
+
+       /* argv[1] is the user's time: e.g.,  3AM */
+       /* argv[2] is a month name or day of week */
+       /* argv[3] is day of month or 'week' */
+       /* another argument might be an input file */
+       if (argc < 2) {
+               fprintf(stderr, "at: arg count\n");
+               exit(1);
+       }
+       makeutime(argv[1]);
+       larg = makeuday(argc, argv) + 1;
+       if (uday == today && larg <= 2 && utimev <= now)
+               uday++;
+       c = uyear % 4 == 0 ? 366 : 365;
+       if (uday >= c) {
+               uday -= c;
+               uyear++;
+       }
+       filename(THISDAY, uyear, uday, utimev);
+       ifile = stdin;
+       if (argc > larg)
+               ifile = fopen(argv[larg], "r");
+       if (ifile == NULL) {
+               fprintf(stderr, "at: cannot open input: %s\n", argv[larg]);
+               exit(1);
+       }
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+               signal(SIGINT, onintr);
+       file = fopen(fname, "a");
+       chmod(fname, 0644);
+       if (file == NULL) {
+               fprintf(stderr, "at: cannot open memo file\n");
+               exit(1);
+       }
+       if ((pwfil = popen("pwd", "r")) == NULL) {
+               fprintf(stderr, "at: can't execute pwd\n");
+               exit(1);
+       }
+       fgets(pwbuf, 100, pwfil);
+       pclose(pwfil);
+       fprintf(file, "cd %s", pwbuf);
+       if (environ) {
+               char **ep = environ;
+               while (*ep)
+                       fprintf(file, "%s\n", *ep++);
+       }
+       while ((c = getc(ifile)) != EOF) {
+               putc(c, file);
+       }
+       exit(0);
+}
diff --git a/Applications/V7/cmd/atrun.c b/Applications/V7/cmd/atrun.c
new file mode 100644 (file)
index 0000000..bab1170
--- /dev/null
@@ -0,0 +1,113 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+/*
+ * Run programs submitted by at.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+# define ATDIR "/usr/spool/at"
+# define PDIR  "past"
+# define LASTF "/usr/spool/at/lasttimedone"
+
+int    nowtime;
+int    nowdate;
+int    nowyear;
+
+void makenowtime(void)
+{
+       time_t t;
+       struct tm *tp;
+
+       time(&t);
+       tp = localtime(&t);
+       nowtime = tp->tm_hour*100 + tp->tm_min;
+       nowdate = tp->tm_yday;
+       nowyear = tp->tm_year;
+}
+
+void updatetime(int t)
+{
+       FILE *tfile;
+
+       tfile = fopen(LASTF, "w");
+       if (tfile == NULL) {
+               fprintf(stderr, "can't write lastfile\n");
+               exit(1);
+       }
+       fprintf(tfile, "%04d\n", t);
+}
+
+void run(char *file)
+{
+       struct stat stbuf;
+       int pid, i;
+       char sbuf[64];
+
+       if (fork()!=0)
+               return;
+       for (i=0; i<15; i++)
+               close(i);
+       dup(dup(open("/dev/null", 0)));
+       /* FIXME: cheaper to do the copy inline */
+       sprintf(sbuf, "/bin/mv %.14s %s", file, PDIR);
+       system(sbuf);
+       chdir(PDIR);
+       if (stat(file, &stbuf) == -1)
+               exit(1);
+       setgid(stbuf.st_gid);
+       setuid(stbuf.st_uid);
+       if (pid = fork()) {
+               if (pid == -1)
+                       exit(1);
+               wait((int *)0);
+               unlink(file);
+               exit(0);
+       }
+       nice(3);
+       execl("/bin/sh", "sh", file, 0);
+       execl("/usr/bin/sh", "sh", file, 0);
+       fprintf(stderr, "Can't execl shell\n");
+       exit(1);
+}
+
+#define DIRSIZ 30
+
+int main(int argc, const char *argv[])
+{
+       int tt, day, year, uniq;
+       struct dirent *d;
+       char file[DIRSIZ+1];
+       DIR *dirf;
+
+       if (chdir(ATDIR) < 0) {
+               fprintf(stderr, "Can't chdir\n");
+               exit(1);
+       }
+       makenowtime();
+       if ((dirf = opendir(".")) == NULL) {
+               fprintf(stderr, "Cannot read at directory\n");
+               exit(1);
+       }
+       while (d = readdir(dirf)) {
+               strncpy(file, d->d_name, DIRSIZ);
+               if (sscanf(file, "%2d.%3d.%4d.%2d", &year, &day, &tt, &uniq) != 4)
+                       continue;
+               if (nowyear < year)
+                       continue;
+               if (nowyear==year && nowdate < day)
+                       continue;
+               if (nowyear==year && nowdate==day && nowtime < tt)
+                       continue;
+               run(file);
+       }
+       closedir(dirf);
+       updatetime(nowtime);
+       exit(0);
+}
diff --git a/Applications/V7/cmd/col.c b/Applications/V7/cmd/col.c
new file mode 100644 (file)
index 0000000..14d144a
--- /dev/null
@@ -0,0 +1,316 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfield for FUZIX */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define PL 256
+#define ESC '\033'
+#define RLF '\013'
+#define SI '\017'
+#define SO '\016'
+#define GREEK 0200
+#define LINELN 800
+
+char *page[PL];
+char lbuff[LINELN], *line;
+int bflag, xflag, fflag;
+int half;
+int cp, lp;
+int ll, llh, mustwr;
+int pcp = 0;
+char *pgmname;
+
+
+void outc(char c)
+{
+       if (lp > cp) {
+               line = lbuff;
+               lp = 0;
+       }
+
+       while (lp < cp) {
+               switch (*line) {
+               case '\0':
+                       *line = ' ';
+                       lp++;
+                       break;
+
+               case '\b':
+                       lp--;
+                       break;
+
+               default:
+                       lp++;
+               }
+               line++;
+       }
+       while (*line == '\b') {
+               line += 2;
+       }
+       if (bflag || *line == '\0' || *line == ' ')
+               *line = c;
+       else {
+               register char c1, c2, c3;
+               c1 = *++line;
+               *line++ = '\b';
+               c2 = *line;
+               *line++ = c;
+               while (c1) {
+                       c3 = *line;
+                       *line++ = c1;
+                       c1 = c2;
+                       c2 = c3;
+               }
+               lp = 0;
+               line = lbuff;
+       }
+}
+
+void store(int lno)
+{
+       lno %= PL;
+       if (page[lno] != 0)
+               free(page[lno]);
+       page[lno] = malloc((unsigned) strlen(lbuff) + 2);
+       if (page[lno] == 0) {
+               fprintf(stderr, "%s: no storage\n", pgmname);
+               exit(2);
+       }
+       strcpy(page[lno], lbuff);
+}
+
+void fetch(int lno)
+{
+       register char *p;
+
+       lno %= PL;
+       p = lbuff;
+       while (*p)
+               *p++ = '\0';
+       line = lbuff;
+       lp = 0;
+       if (page[lno])
+               strcpy(line, page[lno]);
+}
+
+void emit(char *s, int lineno)
+{
+       static int cline = 0;
+       register int ncp;
+       register char *p;
+       static int gflag = 0;
+
+       if (*s) {
+               if (gflag) {
+                       putchar(SI);
+                       gflag = 0;
+               }
+               while (cline < lineno - 1) {
+                       putchar('\n');
+                       pcp = 0;
+                       cline += 2;
+               }
+               if (cline != lineno) {
+                       putchar(ESC);
+                       putchar('9');
+                       cline++;
+               }
+               if (pcp)
+                       putchar('\r');
+               pcp = 0;
+               p = s;
+               while (*p) {
+                       ncp = pcp;
+                       while (*p++ == ' ') {
+                               if ((++ncp & 7) == 0 && !xflag) {
+                                       pcp = ncp;
+                                       putchar('\t');
+                               }
+                       }
+                       if (!*--p)
+                               break;
+                       while (pcp < ncp) {
+                               putchar(' ');
+                               pcp++;
+                       }
+                       if (gflag != (*p & GREEK) && *p != '\b') {
+                               if (gflag)
+                                       putchar(SI);
+                               else
+                                       putchar(SO);
+                               gflag ^= GREEK;
+                       }
+                       putchar(*p & ~GREEK);
+                       if (*p++ == '\b')
+                               pcp--;
+                       else
+                               pcp++;
+               }
+       }
+}
+
+void incr(void)
+{
+       store(ll++);
+       if (ll > llh)
+               llh = ll;
+       if (ll >= mustwr && page[ll % PL]) {
+               emit(page[ll % PL], ll - PL);
+               mustwr++;
+               free(page[ll % PL]);
+               page[ll % PL] = 0;
+       }
+       fetch(ll);
+}
+
+void decr(void)
+{
+       if (ll > mustwr - PL) {
+               store(ll--);
+               fetch(ll);
+       }
+}
+
+int main(int argc, const char *argv[])
+{
+       int i;
+       int greek;
+       register int c;
+       char fbuff[BUFSIZ];
+
+       setbuf(stdout, fbuff);
+       pgmname = argv[0];
+
+       for (i = 1; i < argc; i++) {
+               register char *p;
+               if (*argv[i] != '-') {
+                       fprintf(stderr, "%s: bad option %s\n",
+                               pgmname, argv[i]);
+                       exit(2);
+               }
+               for (p = argv[i] + 1; *p; p++) {
+                       switch (*p) {
+                       case 'b':
+                               bflag++;
+                               break;
+
+                       case 'x':
+                               xflag++;
+                               break;
+
+                       case 'f':
+                               fflag++;
+                               break;
+
+                       default:
+                               fprintf(stderr,
+                                       "%s: bad option letter %c\n",
+                                       pgmname, *p);
+                               exit(2);
+                       }
+               }
+       }
+
+       for (ll = 0; ll < PL; ll++)
+               page[ll] = 0;
+
+       cp = 0;
+       ll = 0;
+       greek = 0;
+       mustwr = PL;
+       line = lbuff;
+
+       while ((c = getchar()) != EOF) {
+               switch (c) {
+               case '\n':
+                       incr();
+                       incr();
+                       cp = 0;
+                       continue;
+
+               case '\0':
+                       continue;
+
+               case ESC:
+                       c = getchar();
+                       switch (c) {
+                       case '7':       /* reverse full line feed */
+                               decr();
+                               decr();
+                               break;
+
+                       case '8':       /* reverse half line feed */
+                               if (fflag)
+                                       decr();
+                               else {
+                                       if (--half < -1) {
+                                               decr();
+                                               decr();
+                                               half += 2;
+                                       }
+                               }
+                               break;
+
+                       case '9':       /* forward half line feed */
+                               if (fflag)
+                                       incr();
+                               else {
+                                       if (++half > 0) {
+                                               incr();
+                                               incr();
+                                               half -= 2;
+                                       }
+                               }
+                               break;
+                       }
+                       continue;
+
+               case SO:
+                       greek = GREEK;
+                       continue;
+
+               case SI:
+                       greek = 0;
+                       continue;
+
+               case RLF:
+                       decr();
+                       decr();
+                       continue;
+
+               case '\r':
+                       cp = 0;
+                       continue;
+
+               case '\t':
+                       cp = (cp + 8) & -8;
+                       continue;
+
+               case '\b':
+                       if (cp > 0)
+                               cp--;
+                       continue;
+
+               case ' ':
+                       cp++;
+                       continue;
+
+               default:
+                       c &= 0177;
+                       if (c > 040 && c < 0177) {      /* if printable */
+                               outc(c | greek);
+                               cp++;
+                       }
+                       continue;
+               }
+       }
+
+       for (i = 0; i < PL; i++)
+               if (page[(mustwr + i) % PL] != 0)
+                       emit(page[(mustwr + i) % PL], mustwr + i - PL);
+       emit(" ", (llh + 1) & -2);
+       return 0;
+}
diff --git a/Applications/V7/cmd/comm.c b/Applications/V7/cmd/comm.c
new file mode 100644 (file)
index 0000000..cfa161e
--- /dev/null
@@ -0,0 +1,177 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LB 256
+int one;
+int two;
+int three;
+
+char ldr[3][3] = { "", "\t", "\t\t" };
+
+FILE *ib1;
+FILE *ib2;
+
+
+FILE *openfil(const char *s)
+{
+       FILE *b;
+       if (s[0] == '-' && s[1] == 0)
+               b = stdin;
+       else if ((b = fopen(s, "r")) == NULL) {
+               fprintf(stderr, "comm: cannot open %s\n", s);
+               exit(1);
+       }
+       return (b);
+}
+
+int rd(FILE * file, char *buf)
+{
+
+       register int i, c;
+       i = 0;
+       while ((c = getc(file)) != EOF) {
+               *buf = c;
+               if (c == '\n' || i > LB - 2) {
+                       *buf = '\0';
+                       return (0);
+               }
+               i++;
+               buf++;
+       }
+       return (-1);
+}
+
+void wr(char *str, int n)
+{
+
+       switch (n) {
+
+       case 1:
+               if (one)
+                       return;
+               break;
+
+       case 2:
+               if (two)
+                       return;
+               break;
+
+       case 3:
+               if (three)
+                       return;
+       }
+       printf("%s%s\n", ldr[n - 1], str);
+}
+
+void copy(FILE * ibuf, char *lbuf, int n)
+{
+       do {
+               wr(lbuf, n);
+       } while (rd(ibuf, lbuf) >= 0);
+
+       exit(0);
+}
+
+int compare(char *a, char *b)
+{
+       register char *ra, *rb;
+
+       ra = --a;
+       rb = --b;
+       while (*++ra == *++rb)
+               if (*ra == '\0')
+                       return (0);
+       if (*ra < *rb)
+               return (1);
+       return (2);
+}
+
+
+int main(int argc, const char *argv[])
+{
+       int l;
+       char lb1[LB], lb2[LB];
+
+       if (argc > 1) {
+               if (*argv[1] == '-' && argv[1][1] != 0) {
+                       l = 1;
+                       while (*++argv[1]) {
+                               switch (*argv[1]) {
+                               case '1':
+                                       if (!one) {
+                                               one = 1;
+                                               ldr[1][0] = '\0';
+                                               ldr[2][l--] = '\0';
+                                       }
+                                       break;
+                               case '2':
+                                       if (!two) {
+                                               two = 1;
+                                               ldr[2][l--] = '\0';
+                                       }
+                                       break;
+                               case '3':
+                                       three = 1;
+                                       break;
+                               default:
+                                       fprintf(stderr,
+                                               "comm: illegal flag\n");
+                                       exit(1);
+                               }
+                       }
+                       argv++;
+                       argc--;
+               }
+       }
+
+       if (argc < 3) {
+               fprintf(stderr, "comm: arg count\n");
+               exit(1);
+       }
+
+       ib1 = openfil(argv[1]);
+       ib2 = openfil(argv[2]);
+
+
+       if (rd(ib1, lb1) < 0) {
+               if (rd(ib2, lb2) < 0)
+                       exit(0);
+               copy(ib2, lb2, 2);
+       }
+       if (rd(ib2, lb2) < 0)
+               copy(ib1, lb1, 1);
+
+       while (1) {
+
+               switch (compare(lb1, lb2)) {
+
+               case 0:
+                       wr(lb1, 3);
+                       if (rd(ib1, lb1) < 0) {
+                               if (rd(ib2, lb2) < 0)
+                                       exit(0);
+                               copy(ib2, lb2, 2);
+                       }
+                       if (rd(ib2, lb2) < 0)
+                               copy(ib1, lb1, 1);
+                       continue;
+
+               case 1:
+                       wr(lb1, 1);
+                       if (rd(ib1, lb1) < 0)
+                               copy(ib2, lb2, 2);
+                       continue;
+
+               case 2:
+                       wr(lb2, 2);
+                       if (rd(ib2, lb2) < 0)
+                               copy(ib1, lb1, 1);
+                       continue;
+               }
+       }
+}
diff --git a/Applications/V7/cmd/cron.c b/Applications/V7/cmd/cron.c
new file mode 100644 (file)
index 0000000..a46859e
--- /dev/null
@@ -0,0 +1,252 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+/* FIXME: hardcoded UID 1 assumption */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#define        LISTS   512
+
+#define        EXACT   100
+#define        ANY     101
+#define        LIST    102
+#define        RANGE   103
+#define        EOS     104
+
+char crontab[] = "/usr/lib/crontab";
+time_t itime;
+struct tm *loct;
+int flag;
+char *list;
+unsigned listsize;
+
+
+char *cmp(char *p, int v)
+{
+       register char *cp;
+
+       cp = p;
+       switch (*cp++) {
+
+       case EXACT:
+               if (*cp++ != v)
+                       flag++;
+               return (cp);
+
+       case ANY:
+               return (cp);
+
+       case LIST:
+               while (*cp != LIST)
+                       if (*cp++ == v) {
+                               while (*cp++ != LIST);
+                               return (cp);
+                       }
+               flag++;
+               return (cp + 1);
+
+       case RANGE:
+               if (*cp > v || cp[1] < v)
+                       flag++;
+               return (cp + 2);
+       }
+       if (cp[-1] != v)
+               flag++;
+       return (cp);
+}
+
+int number(int c)
+{
+       int n = 0;
+
+       while (isdigit(c)) {
+               n = n * 10 + c - '0';
+               c = getchar();
+       }
+       ungetc(c, stdin);
+       if (n >= 100)
+               return (-1);
+       return (n);
+}
+
+
+void slp(void)
+{
+       int i;
+       time_t t;
+
+       time(&t);
+       i = itime - t;
+       if (i > 0)
+               sleep(i);
+}
+
+void ex(char *s)
+{
+       int st;
+
+       if (fork()) {
+               wait(&st);
+               return;
+       }
+       if (fork())
+               exit(0);
+       freopen("/", "r", stdin);
+       execl("/bin/sh", "sh", "-c", s, 0);
+       exit(0);
+}
+
+void init(void)
+{
+       register i, c;
+       register char *cp;
+       register char *ocp;
+       register int n;
+
+       freopen(crontab, "r", stdin);
+       if (list) {
+               free(list);
+               list = realloc(list, LISTS);
+       } else
+               list = malloc(LISTS);
+       listsize = LISTS;
+       cp = list;
+
+      loop:
+       if (cp > list + listsize - 100) {
+               char *olist;
+               listsize += LISTS;
+               olist = list;
+               free(list);
+               list = realloc(list, listsize);
+               cp = list + (cp - olist);
+       }
+       ocp = cp;
+       for (i = 0;; i++) {
+               do
+                       c = getchar();
+               while (c == ' ' || c == '\t');
+               if (c == EOF || c == '\n')
+                       goto ignore;
+               if (i == 5)
+                       break;
+               if (c == '*') {
+                       *cp++ = ANY;
+                       continue;
+               }
+               if ((n = number(c)) < 0)
+                       goto ignore;
+               c = getchar();
+               if (c == ',')
+                       goto mlist;
+               if (c == '-')
+                       goto mrange;
+               if (c != '\t' && c != ' ')
+                       goto ignore;
+               *cp++ = EXACT;
+               *cp++ = n;
+               continue;
+
+             mlist:
+               *cp++ = LIST;
+               *cp++ = n;
+               do {
+                       if ((n = number(getchar())) < 0)
+                               goto ignore;
+                       *cp++ = n;
+                       c = getchar();
+               } while (c == ',');
+               if (c != '\t' && c != ' ')
+                       goto ignore;
+               *cp++ = LIST;
+               continue;
+
+             mrange:
+               *cp++ = RANGE;
+               *cp++ = n;
+               if ((n = number(getchar())) < 0)
+                       goto ignore;
+               c = getchar();
+               if (c != '\t' && c != ' ')
+                       goto ignore;
+               *cp++ = n;
+       }
+       while (c != '\n') {
+               if (c == EOF)
+                       goto ignore;
+               if (c == '%')
+                       c = '\n';
+               *cp++ = c;
+               c = getchar();
+       }
+       *cp++ = '\n';
+       *cp++ = 0;
+       goto loop;
+
+      ignore:
+       cp = ocp;
+       while (c != '\n') {
+               if (c == EOF) {
+                       *cp++ = EOS;
+                       *cp++ = EOS;
+                       fclose(stdin);
+                       return;
+               }
+               c = getchar();
+       }
+       goto loop;
+}
+
+int main(int argc, char *argv[])
+{
+       register char *cp;
+       time_t filetime = 0;
+
+       setuid(1);
+       if (fork())
+               exit(0);
+       chdir("/");
+       freopen(crontab, "r", stdin);
+       freopen("/", "r", stdout);
+       freopen("/", "r", stderr);
+       signal(SIGHUP, SIG_IGN);
+       signal(SIGINT, SIG_IGN);
+       signal(SIGQUIT, SIG_IGN);
+       time(&itime);
+       itime -= localtime(&itime)->tm_sec;
+       fclose(stdin);
+
+       for (;; itime += 60, slp()) {
+               struct stat cstat;
+
+               if (stat(crontab, &cstat) == -1)
+                       continue;
+               if (cstat.st_mtime > filetime) {
+                       filetime = cstat.st_mtime;
+                       init();
+               }
+               loct = localtime(&itime);
+               loct->tm_mon++; /* 1-12 for month */
+               for (cp = list; *cp != EOS;) {
+                       flag = 0;
+                       cp = cmp(cp, loct->tm_min);
+                       cp = cmp(cp, loct->tm_hour);
+                       cp = cmp(cp, loct->tm_mday);
+                       cp = cmp(cp, loct->tm_mon);
+                       cp = cmp(cp, loct->tm_wday);
+                       if (flag == 0) {
+                               slp();
+                               ex(cp);
+                       }
+                       while (*cp++ != 0);
+               }
+       }
+}
diff --git a/Applications/V7/cmd/crypt.c b/Applications/V7/cmd/crypt.c
new file mode 100644 (file)
index 0000000..e822bde
--- /dev/null
@@ -0,0 +1,97 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+/* FIXME: this is *not* strong crypto */
+
+/*
+ *     A one-rotor machine designed along the lines of Enigma
+ *     but considerably trivialized.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ROTORSZ 256
+#define MASK 0377
+
+char   t1[ROTORSZ];
+char   t2[ROTORSZ];
+char   t3[ROTORSZ];
+
+void setup(char *pw)
+{
+       int ic, i, k, temp, pf[2];
+       unsigned random;
+       char buf[13];
+       long seed;
+
+       strncpy(buf, pw, 8);
+       while (*pw)
+               *pw++ = '\0';
+       buf[8] = buf[0];
+       buf[9] = buf[1];
+       pipe(pf);
+       if (fork()==0) {
+               close(0);
+               close(1);
+               dup(pf[0]);
+               dup(pf[1]);
+               execl("/usr/lib/makekey", "-", 0);
+               execl("/lib/makekey", "-", 0);
+               exit(1);
+       }
+       write(pf[1], buf, 10);
+       wait((int *)NULL);
+       if (read(pf[0], buf, 13) != 13) {
+               fprintf(stderr, "crypt: cannot generate key\n");
+               exit(1);
+       }
+       seed = 123;
+       for (i=0; i<13; i++)
+               seed = seed*buf[i] + i;
+       for(i=0;i<ROTORSZ;i++)
+               t1[i] = i;
+       for(i=0;i<ROTORSZ;i++) {
+               seed = 5*seed + buf[i%13];
+               random = seed % 65521;
+               k = ROTORSZ-1 - i;
+               ic = (random&MASK)%(k+1);
+               random >>= 8;
+               temp = t1[k];
+               t1[k] = t1[ic];
+               t1[ic] = temp;
+               if(t3[k]!=0) continue;
+               ic = (random&MASK) % k;
+               while(t3[ic]!=0) ic = (ic+1) % k;
+               t3[k] = ic;
+               t3[ic] = k;
+       }
+       for(i=0;i<ROTORSZ;i++)
+               t2[t1[i]&MASK] = i;
+}
+
+int main(int argc, const char *argv[])
+{
+       int i, n1, n2;
+
+       if (argc != 2){
+               setup(getpass("Enter key:"));
+       }
+       else
+               setup(argv[1]);
+       n1 = 0;
+       n2 = 0;
+
+       while((i=getchar()) >=0) {
+               i = t2[(t3[(t1[(i+n1)&MASK]+n2)&MASK]-n2)&MASK]-n1;
+               putchar(i);
+               n1++;
+               if(n1==ROTORSZ) {
+                       n1 = 0;
+                       n2++;
+                       if(n2==ROTORSZ) n2 = 0;
+               }
+       }
+}
diff --git a/Applications/V7/cmd/dc.c b/Applications/V7/cmd/dc.c
new file mode 100644 (file)
index 0000000..ba86a5c
--- /dev/null
@@ -0,0 +1,2191 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfield for FUZIX */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+
+#define FATAL 0
+#define NFATAL 1
+#define BLK sizeof(struct blk)
+#define PTRSZ sizeof(int *)
+#define HEADSZ 1024
+#define STKSZ 100
+#define RDSKSZ 100
+#define TBLSZ 256
+#define ARRAYST 0241
+#define MAXIND 2048
+#define NL 1
+#define NG 2
+#define NE 3
+#define length(p) ((p)->wt-(p)->beg)
+#define rewind(p) (p)->rd=(p)->beg
+#define create(p)      (p)->rd = (p)->wt = (p)->beg
+#define fsfile(p)      (p)->rd = (p)->wt
+#define truncate(p)    (p)->wt = (p)->rd
+#define sfeof(p)       (((p)->rd==(p)->wt)?1:0)
+#define sfbeg(p)       (((p)->rd==(p)->beg)?1:0)
+#define sungetc(p,c)   *(--(p)->rd)=c
+#define sgetc(p)       (((p)->rd==(p)->wt)?EOF:*(p)->rd++)
+#define slookc(p)      (((p)->rd==(p)->wt)?EOF:*(p)->rd)
+#define sbackc(p)      (((p)->rd==(p)->beg)?EOF:*(--(p)->rd))
+#define sputc(p,c)     {if((p)->wt==(p)->last)more(p); *(p)->wt++ = c; }
+#define salterc(p,c)   {if((p)->rd==(p)->last)more(p); *(p)->rd++ = c; if((p)->rd>(p)->wt)(p)->wt=(p)->rd;}
+#define sunputc(p)     (*( (p)->rd = --(p)->wt))
+#define zero(p)        for(pp=(p)->beg;pp<(p)->last;)*pp++='\0'
+#define OUTC(x) {printf("%c",x); if(--count == 0){printf("\\\n"); count=ll;} }
+#define TEST2  {if((count -= 2) <=0){printf("\\\n");count=ll;}}
+#define EMPTY if(stkerr != 0){printf("stack empty\n"); continue; }
+#define EMPTYR(x) if(stkerr!=0){pushp(x);printf("stack empty\n");continue;}
+#define EMPTYS if(stkerr != 0){printf("stack empty\n"); return(1);}
+#define EMPTYSR(x) if(stkerr !=0){printf("stack empty\n");pushp(x);return(1);}
+#define error(p)       {printf(p); continue; }
+#define errorrt(p)     {printf(p); return(1); }
+
+struct blk {
+       char *rd;
+       char *wt;
+       char *beg;
+       char *last;
+};
+struct sym {
+       struct sym *next;
+       struct blk *val;
+} symlst[TBLSZ];
+struct wblk {
+       struct blk **rdw;
+       struct blk **wtw;
+       struct blk **begw;
+       struct blk **lastw;
+};
+
+struct blk *hfree;
+struct blk *getwd(struct blk *p);
+struct blk *lookwd(struct blk *p);
+struct blk *getdec(struct blk *p, int sc);
+struct blk *morehd(void);
+void release(struct blk *p);
+void putwd(struct blk *p, struct blk *c);
+char *nalloc(char *p, unsigned nbytes);
+void redef(struct blk *p);
+void garbage(char *s);
+void ospace(char *s);
+void more(struct blk *hptr);
+void salterwd(struct wblk *hptr, struct blk *n);
+void seekc(struct blk *hptr, int n);
+void sdump(char *s1, struct blk *hptr);
+struct blk *copy(struct blk *hptr, int size);
+struct blk *salloc(int size);
+int log2(long n);
+void load(void);
+int cond(char c);
+int command(void);
+int subt(void);
+struct blk *scale(struct blk *p, int n);
+struct blk *removc(struct blk *p, int n);
+int eqk(void);
+struct blk *add(struct blk *a1, struct blk *a2);
+void bigot(struct blk *p, int flg);
+void hexot(struct blk *p, int flg);
+void oneot(struct blk *p, int sc, char ch);
+void tenot(struct blk *p, int sc);
+void print(struct blk *hptr);
+void binop(char c);
+void unreadc(char c);
+int readc(void);
+void chsign(struct blk *p);
+struct blk *mult(struct blk *p, struct blk *q);
+struct blk *add0(struct blk *p, int ct);
+struct blk *readin(void);
+struct blk *pop(void);
+void pushp(struct blk *p);
+void onintr(int sig);
+void init(int argc, char *argv[]);
+struct blk *exp(struct blk *base, struct blk *ex);
+struct blk *sqrt(struct blk *p);
+struct blk *removr(struct blk *p, int n);
+int dscale(void);
+struct blk *scalint(struct blk *p);
+struct blk *div(struct blk *ddivd, struct blk *ddivr);
+void commnds(void);
+
+struct blk *arg1, *arg2;
+int svargc;
+char savk;
+char **svargv;
+int dbg;
+int ifile;
+FILE *curfile;
+struct blk *scalptr, *basptr, *tenptr, *inbas;
+struct blk *sqtemp, *chptr, *strptr, *divxyz;
+struct blk *stack[STKSZ];
+struct blk **stkptr, **stkbeg;
+struct blk **stkend;
+int stkerr;
+int lastchar;
+struct blk *readstk[RDSKSZ];
+struct blk **readptr;
+struct blk *rem;
+int k;
+struct blk *irem;
+int skd, skr;
+int neg;
+struct sym *stable[TBLSZ];
+struct sym *sptr, *sfree;
+FILE *fsave;
+long rel;
+long nbytes;
+long all;
+long headmor;
+long obase;
+int fw, fw1, ll;
+void (*outdit) (struct blk *, int);
+int logo;
+int log10;
+int count;
+char *pp;
+char *dummy;
+
+int main(int argc, char *argv[])
+{
+       init(argc, argv);
+       commnds();
+}
+
+void commnds(void)
+{
+       register int c;
+       register struct blk *p, *q;
+       long l;
+       int sign;
+       struct blk **ptr, *s, *t;
+       struct sym *sp;
+       int sk, sk1, sk2;
+       int n, d;
+
+       while (1) {
+               if (((c = readc()) >= '0' && c <= '9')
+                   || (c >= 'A' && c <= 'F') || c == '.') {
+                       unreadc(c);
+                       p = readin();
+                       pushp(p);
+                       continue;
+               }
+               switch (c) {
+               case ' ':
+               case '\n':
+               case 0377:
+               case EOF:
+                       continue;
+               case 'Y':
+                       sdump("stk", *stkptr);
+                       printf("all %ld rel %ld headmor %ld\n", all, rel,
+                              headmor);
+                       printf("nbytes %ld\n", nbytes);
+                       continue;
+               case '_':
+                       p = readin();
+                       savk = sunputc(p);
+                       chsign(p);
+                       sputc(p, savk);
+                       pushp(p);
+                       continue;
+               case '-':
+                       subt();
+                       continue;
+               case '+':
+                       if (eqk() != 0)
+                               continue;
+                       binop('+');
+                       continue;
+               case '*':
+                       arg1 = pop();
+                       EMPTY;
+                       arg2 = pop();
+                       EMPTYR(arg1);
+                       sk1 = sunputc(arg1);
+                       sk2 = sunputc(arg2);
+                       binop('*');
+                       p = pop();
+                       sunputc(p);
+                       savk = sk1 + sk2;
+                       if (savk > k && savk > sk1 && savk > sk2) {
+                               sk = sk1;
+                               if (sk < sk2)
+                                       sk = sk2;
+                               if (sk < k)
+                                       sk = k;
+                               p = removc(p, savk - sk);
+                               savk = sk;
+                       }
+                       sputc(p, savk);
+                       pushp(p);
+                       continue;
+               case '/':
+                     casediv:
+                       if (dscale() != 0)
+                               continue;
+                       binop('/');
+                       if (irem != 0)
+                               release(irem);
+                       release(rem);
+                       continue;
+               case '%':
+                       if (dscale() != 0)
+                               continue;
+                       binop('/');
+                       p = pop();
+                       release(p);
+                       if (irem == 0) {
+                               sputc(rem, skr + k);
+                               pushp(rem);
+                               continue;
+                       }
+                       p = add0(rem, skd - (skr + k));
+                       q = add(p, irem);
+                       release(p);
+                       release(irem);
+                       sputc(q, skd);
+                       pushp(q);
+                       continue;
+               case 'v':
+                       p = pop();
+                       EMPTY;
+                       savk = sunputc(p);
+                       if (length(p) == 0) {
+                               sputc(p, savk);
+                               pushp(p);
+                               continue;
+                       }
+                       if ((c = sbackc(p)) < 0) {
+                               error("sqrt of neg number\n");
+                       }
+                       if (k < savk)
+                               n = savk;
+                       else {
+                               n = k * 2 - savk;
+                               savk = k;
+                       }
+                       arg1 = add0(p, n);
+                       arg2 = sqrt(arg1);
+                       sputc(arg2, savk);
+                       pushp(arg2);
+                       continue;
+               case '^':
+                       neg = 0;
+                       arg1 = pop();
+                       EMPTY;
+                       if (sunputc(arg1) != 0)
+                               error("exp not an integer\n");
+                       arg2 = pop();
+                       EMPTYR(arg1);
+                       if (sfbeg(arg1) == 0 && sbackc(arg1) < 0) {
+                               neg++;
+                               chsign(arg1);
+                       }
+                       if (length(arg1) >= 3) {
+                               error("exp too big\n");
+                       }
+                       savk = sunputc(arg2);
+                       p = exp(arg2, arg1);
+                       release(arg2);
+                       rewind(arg1);
+                       c = sgetc(arg1);
+                       if (sfeof(arg1) == 0)
+                               c = sgetc(arg1) * 100 + c;
+                       d = c * savk;
+                       release(arg1);
+                       if (neg == 0) {
+                               if (k >= savk)
+                                       n = k;
+                               else
+                                       n = savk;
+                               if (n < d) {
+                                       q = removc(p, d - n);
+                                       sputc(q, n);
+                                       pushp(q);
+                               } else {
+                                       sputc(p, d);
+                                       pushp(p);
+                               }
+                       } else {
+                               sputc(p, d);
+                               pushp(p);
+                       }
+                       if (neg == 0)
+                               continue;
+                       p = pop();
+                       q = salloc(2);
+                       sputc(q, 1);
+                       sputc(q, 0);
+                       pushp(q);
+                       pushp(p);
+                       goto casediv;
+               case 'z':
+                       p = salloc(2);
+                       n = stkptr - stkbeg;
+                       if (n >= 100) {
+                               sputc(p, n / 100);
+                               n %= 100;
+                       }
+                       sputc(p, n);
+                       sputc(p, 0);
+                       pushp(p);
+                       continue;
+               case 'Z':
+                       p = pop();
+                       EMPTY;
+                       n = (length(p) - 1) << 1;
+                       fsfile(p);
+                       sbackc(p);
+                       if (sfbeg(p) == 0) {
+                               if ((c = sbackc(p)) < 0) {
+                                       n -= 2;
+                                       if (sfbeg(p) == 1)
+                                               n += 1;
+                                       else {
+                                               if ((c = sbackc(p)) == 0)
+                                                       n += 1;
+                                               else if (c > 90)
+                                                       n -= 1;
+                                       }
+                               } else if (c < 10)
+                                       n -= 1;
+                       }
+                       release(p);
+                       q = salloc(1);
+                       if (n >= 100) {
+                               sputc(q, n % 100);
+                               n /= 100;
+                       }
+                       sputc(q, n);
+                       sputc(q, 0);
+                       pushp(q);
+                       continue;
+               case 'i':
+                       p = pop();
+                       EMPTY;
+                       p = scalint(p);
+                       release(inbas);
+                       inbas = p;
+                       continue;
+               case 'I':
+                       p = copy(inbas, length(inbas) + 1);
+                       sputc(p, 0);
+                       pushp(p);
+                       continue;
+               case 'o':
+                       p = pop();
+                       EMPTY;
+                       p = scalint(p);
+                       sign = 0;
+                       n = length(p);
+                       q = copy(p, n);
+                       fsfile(q);
+                       l = c = sbackc(q);
+                       if (n != 1) {
+                               if (c < 0) {
+                                       sign = 1;
+                                       chsign(q);
+                                       n = length(q);
+                                       fsfile(q);
+                                       l = c = sbackc(q);
+                               }
+                               if (n != 1) {
+                                       while (sfbeg(q) == 0)
+                                               l = l * 100 + sbackc(q);
+                               }
+                       }
+                       logo = log2(l);
+                       obase = l;
+                       release(basptr);
+                       if (sign == 1)
+                               obase = -l;
+                       basptr = p;
+                       outdit = bigot;
+                       if (n == 1 && sign == 0) {
+                               if (c <= 16) {
+                                       outdit = hexot;
+                                       fw = 1;
+                                       fw1 = 0;
+                                       ll = 70;
+                                       release(q);
+                                       continue;
+                               }
+                       }
+                       n = 0;
+                       if (sign == 1)
+                               n++;
+                       p = salloc(1);
+                       sputc(p, -1);
+                       t = add(p, q);
+                       n += length(t) * 2;
+                       fsfile(t);
+                       if ((c = sbackc(t)) > 9)
+                               n++;
+                       release(t);
+                       release(q);
+                       release(p);
+                       fw = n;
+                       fw1 = n - 1;
+                       ll = 70;
+                       if (fw >= ll)
+                               continue;
+                       ll = (70 / fw) * fw;
+                       continue;
+               case 'O':
+                       p = copy(basptr, length(basptr) + 1);
+                       sputc(p, 0);
+                       pushp(p);
+                       continue;
+               case '[':
+                       n = 0;
+                       p = salloc(0);
+                       while (1) {
+                               if ((c = readc()) == ']') {
+                                       if (n == 0)
+                                               break;
+                                       n--;
+                               }
+                               sputc(p, c);
+                               if (c == '[')
+                                       n++;
+                       }
+                       pushp(p);
+                       continue;
+               case 'k':
+                       p = pop();
+                       EMPTY;
+                       p = scalint(p);
+                       if (length(p) > 1) {
+                               error("scale too big\n");
+                       }
+                       rewind(p);
+                       k = sfeof(p) ? 0 : sgetc(p);
+                       release(scalptr);
+                       scalptr = p;
+                       continue;
+               case 'K':
+                       p = copy(scalptr, length(scalptr) + 1);
+                       sputc(p, 0);
+                       pushp(p);
+                       continue;
+               case 'X':
+                       p = pop();
+                       EMPTY;
+                       fsfile(p);
+                       n = sbackc(p);
+                       release(p);
+                       p = salloc(2);
+                       sputc(p, n);
+                       sputc(p, 0);
+                       pushp(p);
+                       continue;
+               case 'Q':
+                       p = pop();
+                       EMPTY;
+                       if (length(p) > 2) {
+                               error("Q?\n");
+                       }
+                       rewind(p);
+                       if ((c = sgetc(p)) < 0) {
+                               error("neg Q\n");
+                       }
+                       release(p);
+                       while (c-- > 0) {
+                               if (readptr == &readstk[0]) {
+                                       error("readstk?\n");
+                               }
+                               if (*readptr != 0)
+                                       release(*readptr);
+                               readptr--;
+                       }
+                       continue;
+               case 'q':
+                       if (readptr <= &readstk[1])
+                               exit(0);
+                       if (*readptr != 0)
+                               release(*readptr);
+                       readptr--;
+                       if (*readptr != 0)
+                               release(*readptr);
+                       readptr--;
+                       continue;
+               case 'f':
+                       if (stkptr == &stack[0])
+                               printf("empty stack\n");
+                       else {
+                               for (ptr = stkptr; ptr > &stack[0];) {
+                                       print(*ptr--);
+                               }
+                       }
+                       continue;
+               case 'p':
+                       if (stkptr == &stack[0])
+                               printf("empty stack\n");
+                       else {
+                               print(*stkptr);
+                       }
+                       continue;
+               case 'P':
+                       p = pop();
+                       EMPTY;
+                       sputc(p, 0);
+                       printf("%s", p->beg);
+                       release(p);
+                       continue;
+               case 'd':
+                       if (stkptr == &stack[0]) {
+                               printf("empty stack\n");
+                               continue;
+                       }
+                       q = *stkptr;
+                       n = length(q);
+                       p = copy(*stkptr, n);
+                       pushp(p);
+                       continue;
+               case 'c':
+                       while (stkerr == 0) {
+                               p = pop();
+                               if (stkerr == 0)
+                                       release(p);
+                       }
+                       continue;
+               case 'S':
+                       if (stkptr == &stack[0]) {
+                               error("save: args\n");
+                       }
+                       c = readc() & 0377;
+                       sptr = stable[c];
+                       sp = stable[c] = sfree;
+                       sfree = sfree->next;
+                       if (sfree == 0)
+                               goto sempty;
+                       sp->next = sptr;
+                       p = pop();
+                       EMPTY;
+                       if (c >= ARRAYST) {
+                               q = copy(p, PTRSZ);
+                               for (n = 0; n < PTRSZ - 1; n++)
+                                       sputc(q, 0);
+                               release(p);
+                               p = q;
+                       }
+                       sp->val = p;
+                       continue;
+                     sempty:
+                       error("symbol table overflow\n");
+               case 's':
+                       if (stkptr == &stack[0]) {
+                               error("save:args\n");
+                       }
+                       c = readc() & 0377;
+                       sptr = stable[c];
+                       if (sptr != 0) {
+                               p = sptr->val;
+                               if (c >= ARRAYST) {
+                                       rewind(p);
+                                       while (sfeof(p) == 0)
+                                               release(getwd(p));
+                               }
+                               release(p);
+                       } else {
+                               sptr = stable[c] = sfree;
+                               sfree = sfree->next;
+                               if (sfree == 0)
+                                       goto sempty;
+                               sptr->next = 0;
+                       }
+                       p = pop();
+                       sptr->val = p;
+                       continue;
+               case 'l':
+                       load();
+                       continue;
+               case 'L':
+                       c = readc() & 0377;
+                       sptr = stable[c];
+                       if (sptr == 0) {
+                               error("L?\n");
+                       }
+                       stable[c] = sptr->next;
+                       sptr->next = sfree;
+                       sfree = sptr;
+                       p = sptr->val;
+                       if (c >= ARRAYST) {
+                               rewind(p);
+                               while (sfeof(p) == 0) {
+                                       q = getwd(p);
+                                       if (q != 0)
+                                               release(q);
+                               }
+                       }
+                       pushp(p);
+                       continue;
+               case ':':
+                       p = pop();
+                       EMPTY;
+                       q = scalint(p);
+                       fsfile(q);
+                       c = 0;
+                       if ((sfbeg(q) == 0) && ((c = sbackc(q)) < 0)) {
+                               error("neg index\n");
+                       }
+                       if (length(q) > 2) {
+                               error("index too big\n");
+                       }
+                       if (sfbeg(q) == 0)
+                               c = c * 100 + sbackc(q);
+                       if (c >= MAXIND) {
+                               error("index too big\n");
+                       }
+                       release(q);
+                       n = readc() & 0377;
+                       sptr = stable[n];
+                       if (sptr == 0) {
+                               sptr = stable[n] = sfree;
+                               sfree = sfree->next;
+                               if (sfree == 0)
+                                       goto sempty;
+                               sptr->next = 0;
+                               p = salloc((c + PTRSZ) * PTRSZ);
+                               zero(p);
+                       } else {
+                               p = sptr->val;
+                               if (length(p) - PTRSZ < c * PTRSZ) {
+                                       q = copy(p, (c + PTRSZ) * PTRSZ);
+                                       release(p);
+                                       p = q;
+                               }
+                       }
+                       seekc(p, c * PTRSZ);
+                       q = lookwd(p);
+                       if (q != NULL)
+                               release(q);
+                       s = pop();
+                       EMPTY;
+                       salterwd((struct wblk *) p, s);
+                       sptr->val = p;
+                       continue;
+               case ';':
+                       p = pop();
+                       EMPTY;
+                       q = scalint(p);
+                       fsfile(q);
+                       c = 0;
+                       if ((sfbeg(q) == 0) && ((c = sbackc(q)) < 0)) {
+                               error("neg index\n");
+                       }
+                       if (length(q) > 2) {
+                               error("index too big\n");
+                       }
+                       if (sfbeg(q) == 0)
+                               c = c * 100 + sbackc(q);
+                       if (c >= MAXIND) {
+                               error("index too big\n");
+                       }
+                       release(q);
+                       n = readc() & 0377;
+                       sptr = stable[n];
+                       if (sptr != 0) {
+                               p = sptr->val;
+                               if (length(p) - PTRSZ >= c * PTRSZ) {
+                                       seekc(p, c * PTRSZ);
+                                       s = getwd(p);
+                                       if (s != 0) {
+                                               q = copy(s, length(s));
+                                               pushp(q);
+                                               continue;
+                                       }
+                               }
+                       }
+                       q = salloc(PTRSZ);
+                       putwd(q, (struct blk *) 0);
+                       pushp(q);
+                       continue;
+               case 'x':
+                     execute:
+                       p = pop();
+                       EMPTY;
+                       if ((readptr != &readstk[0]) && (*readptr != 0)) {
+                               if ((*readptr)->rd == (*readptr)->wt)
+                                       release(*readptr);
+                               else {
+                                       if (readptr++ == &readstk[RDSKSZ]) {
+                                               error("nesting depth\n");
+                                       }
+                               }
+                       } else
+                               readptr++;
+                       *readptr = p;
+                       if (p != 0)
+                               rewind(p);
+                       else {
+                               if ((c = readc()) != '\n')
+                                       unreadc(c);
+                       }
+                       continue;
+               case '?':
+                       if (++readptr == &readstk[RDSKSZ]) {
+                               error("nesting depth\n");
+                       }
+                       *readptr = 0;
+                       fsave = curfile;
+                       curfile = stdin;
+                       while ((c = readc()) == '!')
+                               command();
+                       p = salloc(0);
+                       sputc(p, c);
+                       while ((c = readc()) != '\n') {
+                               sputc(p, c);
+                               if (c == '\\')
+                                       sputc(p, readc());
+                       }
+                       curfile = fsave;
+                       *readptr = p;
+                       continue;
+               case '!':
+                       if (command() == 1)
+                               goto execute;
+                       continue;
+               case '<':
+               case '>':
+               case '=':
+                       if (cond(c) == 1)
+                               goto execute;
+                       continue;
+               default:
+                       printf("%o is unimplemented\n", c);
+               }
+       }
+}
+
+struct blk *div(struct blk *ddivd, struct blk *ddivr)
+{
+       int divsign, remsign, offset, divcarry;
+       int carry, dig, magic, d, dd;
+       long c, td, cc;
+       struct blk *ps;
+       register struct blk *p, *divd, *divr;
+
+       rem = 0;
+       p = salloc(0);
+       if (length(ddivr) == 0) {
+               pushp(ddivr);
+               errorrt("divide by 0\n");
+       }
+       divsign = remsign = 0;
+       divr = ddivr;
+       fsfile(divr);
+       if (sbackc(divr) == -1) {
+               divr = copy(ddivr, length(ddivr));
+               chsign(divr);
+               divsign = ~divsign;
+       }
+       divd = copy(ddivd, length(ddivd));
+       fsfile(divd);
+       if (sfbeg(divd) == 0 && sbackc(divd) == -1) {
+               chsign(divd);
+               divsign = ~divsign;
+               remsign = ~remsign;
+       }
+       offset = length(divd) - length(divr);
+       if (offset < 0)
+               goto ddone;
+       seekc(p, offset + 1);
+       sputc(divd, 0);
+       magic = 0;
+       fsfile(divr);
+       c = sbackc(divr);
+       if (c < 10)
+               magic++;
+       c = c * 100 + (sfbeg(divr) ? 0 : sbackc(divr));
+       if (magic > 0) {
+               c = (c * 100 + (sfbeg(divr) ? 0 : sbackc(divr))) * 2;
+               c /= 25;
+       }
+       while (offset >= 0) {
+               fsfile(divd);
+               td = sbackc(divd) * 100;
+               dd = sfbeg(divd) ? 0 : sbackc(divd);
+               td = (td + dd) * 100;
+               dd = sfbeg(divd) ? 0 : sbackc(divd);
+               td = td + dd;
+               cc = c;
+               if (offset == 0)
+                       td += 1;
+               else
+                       cc += 1;
+               if (magic != 0)
+                       td = td << 3;
+               dig = td / cc;
+               rewind(divr);
+               rewind(divxyz);
+               carry = 0;
+               while (sfeof(divr) == 0) {
+                       d = sgetc(divr) * dig + carry;
+                       carry = d / 100;
+                       salterc(divxyz, d % 100);
+               }
+               salterc(divxyz, carry);
+               rewind(divxyz);
+               seekc(divd, offset);
+               carry = 0;
+               while (sfeof(divd) == 0) {
+                       d = slookc(divd);
+                       d = d - (sfeof(divxyz) ? 0 : sgetc(divxyz)) -
+                           carry;
+                       carry = 0;
+                       if (d < 0) {
+                               d += 100;
+                               carry = 1;
+                       }
+                       salterc(divd, d);
+               }
+               divcarry = carry;
+               sbackc(p);
+               salterc(p, dig);
+               sbackc(p);
+               if (--offset >= 0)
+                       divd->wt--;
+       }
+       if (divcarry != 0) {
+               salterc(p, dig - 1);
+               salterc(divd, -1);
+               ps = add(divr, divd);
+               release(divd);
+               divd = ps;
+       }
+
+       rewind(p);
+       divcarry = 0;
+       while (sfeof(p) == 0) {
+               d = slookc(p) + divcarry;
+               divcarry = 0;
+               if (d >= 100) {
+                       d -= 100;
+                       divcarry = 1;
+               }
+               salterc(p, d);
+       }
+       if (divcarry != 0)
+               salterc(p, divcarry);
+       fsfile(p);
+       while (sfbeg(p) == 0) {
+               if (sbackc(p) == 0)
+                       truncate(p);
+               else
+                       break;
+       }
+       if (divsign < 0)
+               chsign(p);
+       fsfile(divd);
+       while (sfbeg(divd) == 0) {
+               if (sbackc(divd) == 0)
+                       truncate(divd);
+               else
+                       break;
+       }
+      ddone:
+       if (remsign < 0)
+               chsign(divd);
+       if (divr != ddivr)
+               release(divr);
+       rem = divd;
+       return (p);
+}
+
+int dscale(void)
+{
+       register struct blk *dd, *dr;
+       register struct blk *r;
+       int c;
+
+       dr = pop();
+       EMPTYS;
+       dd = pop();
+       EMPTYSR(dr);
+       fsfile(dd);
+       skd = sunputc(dd);
+       fsfile(dr);
+       skr = sunputc(dr);
+       if (sfbeg(dr) == 1 || (sfbeg(dr) == 0 && sbackc(dr) == 0)) {
+               sputc(dr, skr);
+               pushp(dr);
+               errorrt("divide by 0\n");
+       }
+       c = k - skd + skr;
+       if (c < 0)
+               r = removr(dd, -c);
+       else {
+               r = add0(dd, c);
+               irem = 0;
+       }
+       arg1 = r;
+       arg2 = dr;
+       savk = k;
+       return (0);
+}
+
+struct blk *removr(struct blk *p, int n)
+{
+       int nn;
+       register struct blk *q, *s, *r;
+
+       rewind(p);
+       nn = (n + 1) / 2;
+       q = salloc(nn);
+       while (n > 1) {
+               sputc(q, sgetc(p));
+               n -= 2;
+       }
+       r = salloc(2);
+       while (sfeof(p) == 0)
+               sputc(r, sgetc(p));
+       release(p);
+       if (n == 1) {
+               s = div(r, tenptr);
+               release(r);
+               rewind(rem);
+               if (sfeof(rem) == 0)
+                       sputc(q, sgetc(rem));
+               release(rem);
+               irem = q;
+               return (s);
+       }
+       irem = q;
+       return (r);
+}
+
+struct blk *sqrt(struct blk *p)
+{
+       struct blk *t;
+       struct blk *r, *q, *s;
+       int c, n, nn;
+
+       n = length(p);
+       fsfile(p);
+       c = sbackc(p);
+       if ((n & 1) != 1)
+               c = c * 100 + (sfbeg(p) ? 0 : sbackc(p));
+       n = (n + 1) >> 1;
+       r = salloc(n);
+       zero(r);
+       seekc(r, n);
+       nn = 1;
+       while ((c -= nn) >= 0)
+               nn += 2;
+       c = (nn + 1) >> 1;
+       fsfile(r);
+       sbackc(r);
+       if (c >= 100) {
+               c -= 100;
+               salterc(r, c);
+               sputc(r, 1);
+       } else
+               salterc(r, c);
+       while (1) {
+               q = div(p, r);
+               s = add(q, r);
+               release(q);
+               release(rem);
+               q = div(s, sqtemp);
+               release(s);
+               release(rem);
+               s = copy(r, length(r));
+               chsign(s);
+               t = add(s, q);
+               release(s);
+               fsfile(t);
+               nn = sfbeg(t) ? 0 : sbackc(t);
+               if (nn >= 0)
+                       break;
+               release(r);
+               release(t);
+               r = q;
+       }
+       release(t);
+       release(q);
+       release(p);
+       return (r);
+}
+
+struct blk *exp(struct blk *base, struct blk *ex)
+{
+       register struct blk *r, *e, *p;
+       struct blk *e1, *t, *cp;
+       int temp, c, n;
+       r = salloc(1);
+       sputc(r, 1);
+       p = copy(base, length(base));
+       e = copy(ex, length(ex));
+       fsfile(e);
+       if (sfbeg(e) != 0)
+               goto edone;
+       temp = 0;
+       c = sbackc(e);
+       if (c < 0) {
+               temp++;
+               chsign(e);
+       }
+       while (length(e) != 0) {
+               e1 = div(e, sqtemp);
+               release(e);
+               e = e1;
+               n = length(rem);
+               release(rem);
+               if (n != 0) {
+                       e1 = mult(p, r);
+                       release(r);
+                       r = e1;
+               }
+               t = copy(p, length(p));
+               cp = mult(p, t);
+               release(p);
+               release(t);
+               p = cp;
+       }
+       if (temp != 0) {
+               if ((c = length(base)) == 0) {
+                       goto edone;
+               }
+               if (c > 1)
+                       create(r);
+               else {
+                       rewind(base);
+                       if ((c = sgetc(base)) <= 1) {
+                               create(r);
+                               sputc(r, c);
+                       } else
+                               create(r);
+               }
+       }
+      edone:
+       release(p);
+       release(e);
+       return (r);
+}
+
+void init(int argc, char *argv[])
+{
+       register struct sym *sp;
+
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+               signal(SIGINT, onintr);
+       setbuf(stdout, (char *) NULL);
+       svargc = --argc;
+       svargv = argv;
+       while (svargc > 0 && svargv[1][0] == '-') {
+               switch (svargv[1][1]) {
+               default:
+                       dbg = 1;
+               }
+               svargc--;
+               svargv++;
+       }
+       ifile = 1;
+       if (svargc <= 0)
+               curfile = stdin;
+       else if ((curfile = fopen(svargv[1], "r")) == NULL) {
+               printf("can't open file %s\n", svargv[1]);
+               exit(1);
+       }
+       dummy = malloc(1);
+       scalptr = salloc(1);
+       sputc(scalptr, 0);
+       basptr = salloc(1);
+       sputc(basptr, 10);
+       obase = 10;
+       log10 = log2(10L);
+       ll = 70;
+       fw = 1;
+       fw1 = 0;
+       tenptr = salloc(1);
+       sputc(tenptr, 10);
+       obase = 10;
+       inbas = salloc(1);
+       sputc(inbas, 10);
+       sqtemp = salloc(1);
+       sputc(sqtemp, 2);
+       chptr = salloc(0);
+       strptr = salloc(0);
+       divxyz = salloc(0);
+       stkbeg = stkptr = &stack[0];
+       stkend = &stack[STKSZ];
+       stkerr = 0;
+       readptr = &readstk[0];
+       k = 0;
+       sp = sptr = &symlst[0];
+       while (sptr < &symlst[TBLSZ]) {
+               sptr->next = ++sp;
+               sptr++;
+       }
+       sptr->next = 0;
+       sfree = &symlst[0];
+       return;
+}
+
+void onintr(int sig)
+{
+
+       signal(SIGINT, onintr);
+       while (readptr != &readstk[0]) {
+               if (*readptr != 0) {
+                       release(*readptr);
+               }
+               readptr--;
+       }
+       curfile = stdin;
+       commnds();
+}
+
+void pushp(struct blk *p)
+{
+       if (stkptr == stkend) {
+               printf("out of stack space\n");
+               return;
+       }
+       stkerr = 0;
+       *++stkptr = p;
+       return;
+}
+
+struct blk *pop(void)
+{
+       if (stkptr == stack) {
+               stkerr = 1;
+               return (0);
+       }
+       return (*stkptr--);
+}
+
+struct blk *readin(void)
+{
+       register struct blk *p, *q;
+       int dp, dpct;
+       register int c;
+
+       dp = dpct = 0;
+       p = salloc(0);
+       while (1) {
+               c = readc();
+               switch (c) {
+               case '.':
+                       if (dp != 0) {
+                               unreadc(c);
+                               break;
+                       }
+                       dp++;
+                       continue;
+               case '\\':
+                       readc();
+                       continue;
+               default:
+                       if (c >= 'A' && c <= 'F')
+                               c = c - 'A' + 10;
+                       else if (c >= '0' && c <= '9')
+                               c -= '0';
+                       else
+                               goto gotnum;
+                       if (dp != 0) {
+                               if (dpct >= 99)
+                                       continue;
+                               dpct++;
+                       }
+                       create(chptr);
+                       if (c != 0)
+                               sputc(chptr, c);
+                       q = mult(p, inbas);
+                       release(p);
+                       p = add(chptr, q);
+                       release(q);
+               }
+       }
+      gotnum:
+       unreadc(c);
+       if (dp == 0) {
+               sputc(p, 0);
+               return (p);
+       } else {
+               q = scale(p, dpct);
+               return (q);
+       }
+}
+
+struct blk *add0(struct blk *p, int ct)
+{
+       /* returns pointer to struct with ct 0's & p */
+       register struct blk *q, *t;
+
+       q = salloc(length(p) + (ct + 1) / 2);
+       while (ct > 1) {
+               sputc(q, 0);
+               ct -= 2;
+       }
+       rewind(p);
+       while (sfeof(p) == 0) {
+               sputc(q, sgetc(p));
+       }
+       release(p);
+       if (ct == 1) {
+               t = mult(tenptr, q);
+               release(q);
+               return (t);
+       }
+       return (q);
+}
+
+struct blk *mult(struct blk *p, struct blk *q)
+{
+       register struct blk *mp, *mq, *mr;
+       int sign, offset, carry;
+       int cq, cp, mt, mcr;
+
+       offset = sign = 0;
+       fsfile(p);
+       mp = p;
+       if (sfbeg(p) == 0) {
+               if (sbackc(p) < 0) {
+                       mp = copy(p, length(p));
+                       chsign(mp);
+                       sign = ~sign;
+               }
+       }
+       fsfile(q);
+       mq = q;
+       if (sfbeg(q) == 0) {
+               if (sbackc(q) < 0) {
+                       mq = copy(q, length(q));
+                       chsign(mq);
+                       sign = ~sign;
+               }
+       }
+       mr = salloc(length(mp) + length(mq));
+       zero(mr);
+       rewind(mq);
+       while (sfeof(mq) == 0) {
+               cq = sgetc(mq);
+               rewind(mp);
+               rewind(mr);
+               mr->rd += offset;
+               carry = 0;
+               while (sfeof(mp) == 0) {
+                       cp = sgetc(mp);
+                       mcr = sfeof(mr) ? 0 : slookc(mr);
+                       mt = cp * cq + carry + mcr;
+                       carry = mt / 100;
+                       salterc(mr, mt % 100);
+               }
+               offset++;
+               if (carry != 0) {
+                       mcr = sfeof(mr) ? 0 : slookc(mr);
+                       salterc(mr, mcr + carry);
+               }
+       }
+       if (sign < 0) {
+               chsign(mr);
+       }
+       if (mp != p)
+               release(mp);
+       if (mq != q)
+               release(mq);
+       return (mr);
+}
+
+void chsign(struct blk *p)
+{
+       register int carry;
+       register char ct;
+
+       carry = 0;
+       rewind(p);
+       while (sfeof(p) == 0) {
+               ct = 100 - slookc(p) - carry;
+               carry = 1;
+               if (ct >= 100) {
+                       ct -= 100;
+                       carry = 0;
+               }
+               salterc(p, ct);
+       }
+       if (carry != 0) {
+               sputc(p, -1);
+               fsfile(p);
+               sbackc(p);
+               ct = sbackc(p);
+               if (ct == 99) {
+                       truncate(p);
+                       sputc(p, -1);
+               }
+       } else {
+               fsfile(p);
+               ct = sbackc(p);
+               if (ct == 0)
+                       truncate(p);
+       }
+       return;
+}
+
+int readc(void)
+{
+      loop:
+       if ((readptr != &readstk[0]) && (*readptr != 0)) {
+               if (sfeof(*readptr) == 0)
+                       return (lastchar = sgetc(*readptr));
+               release(*readptr);
+               readptr--;
+               goto loop;
+       }
+       lastchar = getc(curfile);
+       if (lastchar != EOF)
+               return (lastchar);
+       if (readptr != &readptr[0]) {
+               readptr--;
+               if (*readptr == 0)
+                       curfile = stdin;
+               goto loop;
+       }
+       if (curfile != stdin) {
+               fclose(curfile);
+               curfile = stdin;
+               goto loop;
+       }
+       exit(0);
+}
+
+void unreadc(char c)
+{
+
+       if ((readptr != &readstk[0]) && (*readptr != 0)) {
+               sungetc(*readptr, c);
+       } else
+               ungetc(c, curfile);
+       return;
+}
+
+void binop(char c)
+{
+       register struct blk *r;
+
+       switch (c) {
+       case '+':
+               r = add(arg1, arg2);
+               break;
+       case '*':
+               r = mult(arg1, arg2);
+               break;
+       case '/':
+               r = div(arg1, arg2);
+               break;
+       }
+       release(arg1);
+       release(arg2);
+       sputc(r, savk);
+       pushp(r);
+       return;
+}
+
+void print(struct blk *hptr)
+{
+       int sc;
+       register struct blk *p, *q, *dec;
+       int dig, dout, ct;
+
+       rewind(hptr);
+       while (sfeof(hptr) == 0) {
+               if (sgetc(hptr) > 99) {
+                       rewind(hptr);
+                       while (sfeof(hptr) == 0) {
+                               printf("%c", sgetc(hptr));
+                       }
+                       printf("\n");
+                       return;
+               }
+       }
+       fsfile(hptr);
+       sc = sbackc(hptr);
+       if (sfbeg(hptr) != 0) {
+               printf("0\n");
+               return;
+       }
+       count = ll;
+       p = copy(hptr, length(hptr));
+       sunputc(p);
+       fsfile(p);
+       if (sbackc(p) < 0) {
+               chsign(p);
+               OUTC('-');
+       }
+       if ((obase == 0) || (obase == -1)) {
+               oneot(p, sc, 'd');
+               return;
+       }
+       if (obase == 1) {
+               oneot(p, sc, '1');
+               return;
+       }
+       if (obase == 10) {
+               tenot(p, sc);
+               return;
+       }
+       create(strptr);
+       dig = log10 * sc;
+       dout = ((dig / 10) + dig) / logo;
+       dec = getdec(p, sc);
+       p = removc(p, sc);
+       while (length(p) != 0) {
+               q = div(p, basptr);
+               release(p);
+               p = q;
+               (*outdit) (rem, 0);
+       }
+       release(p);
+       fsfile(strptr);
+       while (sfbeg(strptr) == 0)
+               OUTC(sbackc(strptr));
+       if (sc == 0) {
+               release(dec);
+               printf("\n");
+               return;
+       }
+       create(strptr);
+       OUTC('.');
+       ct = 0;
+       do {
+               q = mult(basptr, dec);
+               release(dec);
+               dec = getdec(q, sc);
+               p = removc(q, sc);
+               (*outdit) (p, 1);
+       } while (++ct < dout);
+       release(dec);
+       rewind(strptr);
+       while (sfeof(strptr) == 0)
+               OUTC(sgetc(strptr));
+       printf("\n");
+       return;
+}
+
+struct blk *getdec(struct blk *p, int sc)
+{
+       int cc;
+       register struct blk *q, *t, *s;
+
+       rewind(p);
+       if (length(p) * 2 < sc) {
+               q = copy(p, length(p));
+               return (q);
+       }
+       q = salloc(length(p));
+       while (sc >= 1) {
+               sputc(q, sgetc(p));
+               sc -= 2;
+       }
+       if (sc != 0) {
+               t = mult(q, tenptr);
+               s = salloc(cc = length(q));
+               release(q);
+               rewind(t);
+               while (cc-- > 0)
+                       sputc(s, sgetc(t));
+               sputc(s, 0);
+               release(t);
+               t = div(s, tenptr);
+               release(s);
+               release(rem);
+               return (t);
+       }
+       return (q);
+}
+
+void tenot(struct blk *p, int sc)
+{
+       register int c, f;
+
+       fsfile(p);
+       f = 0;
+       while ((sfbeg(p) == 0) && ((p->rd - p->beg - 1) * 2 >= sc)) {
+               c = sbackc(p);
+               if ((c < 10) && (f == 1))
+                       printf("0%d", c);
+               else
+                       printf("%d", c);
+               f = 1;
+               TEST2;
+       }
+       if (sc == 0) {
+               printf("\n");
+               release(p);
+               return;
+       }
+       if ((p->rd - p->beg) * 2 > sc) {
+               c = sbackc(p);
+               printf("%d.", c / 10);
+               TEST2;
+               OUTC(c % 10 + '0');
+               sc--;
+       } else {
+               OUTC('.');
+       }
+       if (sc > (p->rd - p->beg) * 2) {
+               while (sc > (p->rd - p->beg) * 2) {
+                       OUTC('0');
+                       sc--;
+               }
+       }
+       while (sc > 1) {
+               c = sbackc(p);
+               if (c < 10)
+                       printf("0%d", c);
+               else
+                       printf("%d", c);
+               sc -= 2;
+               TEST2;
+       }
+       if (sc == 1) {
+               OUTC(sbackc(p) / 10 + '0');
+       }
+       printf("\n");
+       release(p);
+       return;
+}
+
+void oneot(struct blk *p, int sc, char ch)
+{
+       register struct blk *q;
+
+       q = removc(p, sc);
+       create(strptr);
+       sputc(strptr, -1);
+       while (length(q) > 0) {
+               p = add(strptr, q);
+               release(q);
+               q = p;
+               OUTC(ch);
+       }
+       release(q);
+       printf("\n");
+       return;
+}
+
+void hexot(struct blk *p, int flg)
+{
+       register int c;
+       rewind(p);
+       if (sfeof(p) != 0) {
+               sputc(strptr, '0');
+               release(p);
+               return;
+       }
+       c = sgetc(p);
+       release(p);
+       if (c >= 16) {
+               printf("hex digit > 16");
+               return;
+       }
+       sputc(strptr, c < 10 ? c + '0' : c - 10 + 'A');
+       return;
+}
+
+void bigot(struct blk *p, int flg)
+{
+       register struct blk *t, *q;
+       register int l;
+       int neg;
+
+       if (flg == 1)
+               t = salloc(0);
+       else {
+               t = strptr;
+               l = length(strptr) + fw - 1;
+       }
+       neg = 0;
+       if (length(p) != 0) {
+               fsfile(p);
+               if (sbackc(p) < 0) {
+                       neg = 1;
+                       chsign(p);
+               }
+               while (length(p) != 0) {
+                       q = div(p, tenptr);
+                       release(p);
+                       p = q;
+                       rewind(rem);
+                       sputc(t, sfeof(rem) ? '0' : sgetc(rem) + '0');
+                       release(rem);
+               }
+       }
+       release(p);
+       if (flg == 1) {
+               l = fw1 - length(t);
+               if (neg != 0) {
+                       l--;
+                       sputc(strptr, '-');
+               }
+               fsfile(t);
+               while (l-- > 0)
+                       sputc(strptr, '0');
+               while (sfbeg(t) == 0)
+                       sputc(strptr, sbackc(t));
+               release(t);
+       } else {
+               l -= length(strptr);
+               while (l-- > 0)
+                       sputc(strptr, '0');
+               if (neg != 0) {
+                       sunputc(strptr);
+                       sputc(strptr, '-');
+               }
+       }
+       sputc(strptr, ' ');
+       return;
+}
+
+struct blk *add(struct blk *a1, struct blk *a2)
+{
+       register struct blk *p;
+       register int carry, n;
+       int size;
+       int c, n1, n2;
+
+       size = length(a1) > length(a2) ? length(a1) : length(a2);
+       p = salloc(size);
+       rewind(a1);
+       rewind(a2);
+       carry = 0;
+       while (--size >= 0) {
+               n1 = sfeof(a1) ? 0 : sgetc(a1);
+               n2 = sfeof(a2) ? 0 : sgetc(a2);
+               n = n1 + n2 + carry;
+               if (n >= 100) {
+                       carry = 1;
+                       n -= 100;
+               } else if (n < 0) {
+                       carry = -1;
+                       n += 100;
+               } else
+                       carry = 0;
+               sputc(p, n);
+       }
+       if (carry != 0)
+               sputc(p, carry);
+       fsfile(p);
+       if (sfbeg(p) == 0) {
+               while (sfbeg(p) == 0 && (c = sbackc(p)) == 0);
+               if (c != 0)
+                       salterc(p, c);
+               truncate(p);
+       }
+       fsfile(p);
+       if (sfbeg(p) == 0 && sbackc(p) == -1) {
+               while ((c = sbackc(p)) == 99) {
+                       if (c == EOF)
+                               break;
+               }
+               sgetc(p);
+               salterc(p, -1);
+               truncate(p);
+       }
+       return (p);
+}
+
+int eqk(void)
+{
+       register struct blk *p, *q;
+       register int skp;
+       int skq;
+
+       p = pop();
+       EMPTYS;
+       q = pop();
+       EMPTYSR(p);
+       skp = sunputc(p);
+       skq = sunputc(q);
+       if (skp == skq) {
+               arg1 = p;
+               arg2 = q;
+               savk = skp;
+               return (0);
+       } else if (skp < skq) {
+               savk = skq;
+               p = add0(p, skq - skp);
+       } else {
+               savk = skp;
+               q = add0(q, skp - skq);
+       }
+       arg1 = p;
+       arg2 = q;
+       return (0);
+}
+
+struct blk *removc(struct blk *p, int n)
+{
+       register struct blk *q, *r;
+
+       rewind(p);
+       while (n > 1) {
+               sgetc(p);
+               n -= 2;
+       }
+       q = salloc(2);
+       while (sfeof(p) == 0)
+               sputc(q, sgetc(p));
+       if (n == 1) {
+               r = div(q, tenptr);
+               release(q);
+               release(rem);
+               q = r;
+       }
+       release(p);
+       return (q);
+}
+
+struct blk *scalint(struct blk *p)
+{
+       register int n;
+       n = sunputc(p);
+       p = removc(p, n);
+       return (p);
+}
+
+struct blk *scale(struct blk *p, int n)
+{
+       register struct blk *q, *s, *t;
+
+       t = add0(p, n);
+       q = salloc(1);
+       sputc(q, n);
+       s = exp(inbas, q);
+       release(q);
+       q = div(t, s);
+       release(t);
+       release(s);
+       release(rem);
+       sputc(q, n);
+       return (q);
+}
+
+int subt(void)
+{
+       arg1 = pop();
+       EMPTYS;
+       savk = sunputc(arg1);
+       chsign(arg1);
+       sputc(arg1, savk);
+       pushp(arg1);
+       if (eqk() != 0)
+               return (1);
+       binop('+');
+       return (0);
+}
+
+int command(void)
+{
+       int c;
+       char line[100], *sl;
+       void (*savint) (int);
+       pid_t pid, rpid;
+       int retcode;
+
+       switch (c = readc()) {
+       case '<':
+               return (cond(NL));
+       case '>':
+               return (cond(NG));
+       case '=':
+               return (cond(NE));
+       default:
+               sl = line;
+               *sl++ = c;
+               while ((c = readc()) != '\n')
+                       *sl++ = c;
+               *sl = 0;
+               if ((pid = fork()) == 0) {
+                       execl("/bin/sh", "sh", "-c", line, 0);
+                       exit(0100);
+               }
+               savint = signal(SIGINT, SIG_IGN);
+               while ((rpid = wait(&retcode)) != pid && rpid != -1);
+               signal(SIGINT, savint);
+               printf("!\n");
+               return (0);
+       }
+}
+
+int cond(char c)
+{
+       register struct blk *p;
+       register char cc;
+
+       if (subt() != 0)
+               return (1);
+       p = pop();
+       sunputc(p);
+       if (length(p) == 0) {
+               release(p);
+               if (c == '<' || c == '>' || c == NE) {
+                       readc();
+                       return (0);
+               }
+               load();
+               return (1);
+       } else {
+               if (c == '=') {
+                       release(p);
+                       readc();
+                       return (0);
+               }
+       }
+       if (c == NE) {
+               release(p);
+               load();
+               return (1);
+       }
+       fsfile(p);
+       cc = sbackc(p);
+       release(p);
+       if ((cc < 0 && (c == '<' || c == NG)) ||
+           (cc > 0) && (c == '>' || c == NL)) {
+               readc();
+               return (0);
+       }
+       load();
+       return (1);
+}
+
+void load(void)
+{
+       register int c;
+       register struct blk *p, *q;
+       struct blk *t, *s;
+       c = readc() & 0377;
+       sptr = stable[c];
+       if (sptr != 0) {
+               p = sptr->val;
+               if (c >= ARRAYST) {
+                       q = salloc(length(p));
+                       rewind(p);
+                       while (sfeof(p) == 0) {
+                               s = getwd(p);
+                               if (s == 0) {
+                                       putwd(q, (struct blk *) NULL);
+                               } else {
+                                       t = copy(s, length(s));
+                                       putwd(q, t);
+                               }
+                       }
+                       pushp(q);
+               } else {
+                       q = copy(p, length(p));
+                       pushp(q);
+               }
+       } else {
+               q = salloc(1);
+               sputc(q, 0);
+               pushp(q);
+       }
+       return;
+}
+
+int log2(long n)
+{
+       register int i;
+
+       if (n == 0)
+               return (0);
+       i = 31;
+       if (n < 0)
+               return (i);
+       while ((n = n << 1) > 0)
+               i--;
+       return (--i);
+}
+
+struct blk *salloc(int size)
+{
+       register struct blk *hdr;
+       register char *ptr;
+       all++;
+       nbytes += size;
+       ptr = malloc((unsigned) size);
+       if (ptr == 0) {
+               garbage("salloc");
+               if ((ptr = malloc((unsigned) size)) == 0)
+                       ospace("salloc");
+       }
+       if ((hdr = hfree) == 0)
+               hdr = morehd();
+       hfree = (struct blk *) hdr->rd;
+       hdr->rd = hdr->wt = hdr->beg = ptr;
+       hdr->last = ptr + size;
+       return (hdr);
+}
+
+struct blk *morehd(void)
+{
+       register struct blk *h, *kk;
+       headmor++;
+       nbytes += HEADSZ;
+       hfree = h = (struct blk *) malloc(HEADSZ);
+       if (hfree == 0) {
+               garbage("morehd");
+               if ((hfree = h = (struct blk *) malloc(HEADSZ)) == 0)
+                       ospace("headers");
+       }
+       kk = h;
+       while (h < hfree + (HEADSZ / BLK))
+               (h++)->rd = (char *) ++kk;
+       (--h)->rd = 0;
+       return (hfree);
+}
+
+/*
+sunputc(struct blk *hptr)
+{
+       hptr->wt--;
+       hptr->rd = hptr->wt;
+       return(*hptr->wt);
+}
+*/
+struct blk *copy(struct blk *hptr, int size)
+{
+       register struct blk *hdr;
+       register unsigned sz;
+       register char *ptr;
+
+       all++;
+       nbytes += size;
+       sz = length(hptr);
+       ptr = nalloc(hptr->beg, (unsigned) size);
+       if (ptr == 0) {
+               garbage("copy");
+               if ((ptr = nalloc(hptr->beg, (unsigned) size)) == NULL) {
+                       printf("copy size %d\n", size);
+                       ospace("copy");
+               }
+       }
+       if ((hdr = hfree) == 0)
+               hdr = morehd();
+       hfree = (struct blk *) hdr->rd;
+       hdr->rd = hdr->beg = ptr;
+       hdr->last = ptr + size;
+       hdr->wt = ptr + sz;
+       ptr = hdr->wt;
+       while (ptr < hdr->last)
+               *ptr++ = '\0';
+       return (hdr);
+}
+
+void sdump(char *s1, struct blk *hptr)
+{
+       char *p;
+       printf("%s %o rd %o wt %o beg %o last %o\n", s1, hptr, hptr->rd,
+              hptr->wt, hptr->beg, hptr->last);
+       p = hptr->beg;
+       while (p < hptr->wt)
+               printf("%d ", *p++);
+       printf("\n");
+}
+
+void seekc(struct blk *hptr, int n)
+{
+       char *nn, *p;
+
+       nn = hptr->beg + n;
+       if (nn > hptr->last) {
+               nbytes += nn - hptr->last;
+               free(hptr->beg);
+               p = realloc(hptr->beg, (unsigned) n);
+               if (p == 0) {
+                       hptr->beg =
+                           realloc(hptr->beg,
+                                   (unsigned) (hptr->last - hptr->beg));
+                       garbage("seekc");
+                       if ((p = realloc(hptr->beg, (unsigned) n)) == 0)
+                               ospace("seekc");
+               }
+               hptr->beg = p;
+               hptr->wt = hptr->last = hptr->rd = p + n;
+               return;
+       }
+       hptr->rd = nn;
+       if (nn > hptr->wt)
+               hptr->wt = nn;
+       return;
+}
+
+void salterwd(struct wblk *hptr, struct blk *n)
+{
+       if (hptr->rdw == hptr->lastw)
+               more((struct blk *) hptr);
+       *hptr->rdw++ = n;
+       if (hptr->rdw > hptr->wtw)
+               hptr->wtw = hptr->rdw;
+       return;
+}
+
+void more(struct blk *hptr)
+{
+       register unsigned size;
+       register char *p;
+
+       if ((size = (hptr->last - hptr->beg) * 2) == 0)
+               size = 1;
+       nbytes += size / 2;
+       free(hptr->beg);
+       p = realloc(hptr->beg, (unsigned) size);
+       if (p == 0) {
+               hptr->beg =
+                   realloc(hptr->beg,
+                           (unsigned) (hptr->last - hptr->beg));
+               garbage("more");
+               if ((p = realloc(hptr->beg, size)) == 0)
+                       ospace("more");
+       }
+       hptr->rd = hptr->rd - hptr->beg + p;
+       hptr->wt = hptr->wt - hptr->beg + p;
+       hptr->beg = p;
+       hptr->last = p + size;
+       return;
+}
+
+void ospace(char *s)
+{
+       printf("out of space: %s\n", s);
+       printf("all %ld rel %ld headmor %ld\n", all, rel, headmor);
+       printf("nbytes %ld\n", nbytes);
+       sdump("stk", *stkptr);
+       abort();
+}
+
+void garbage(char *s)
+{
+       int i;
+       struct blk *p, *q;
+       struct sym *tmps;
+       int ct;
+
+/*     printf("got to garbage %s\n",s);        */
+       for (i = 0; i < TBLSZ; i++) {
+               tmps = stable[i];
+               if (tmps != 0) {
+                       if (i < ARRAYST) {
+                               do {
+                                       p = tmps->val;
+                                       if (((int) p->beg & 01) != 0) {
+                                               printf("string %o\n", i);
+                                               sdump("odd beg", p);
+                                       }
+                                       redef(p);
+                                       tmps = tmps->next;
+                               } while (tmps != 0);
+                               continue;
+                       } else {
+                               do {
+                                       p = tmps->val;
+                                       rewind(p);
+                                       ct = 0;
+                                       while ((q = getwd(p)) != NULL) {
+                                               ct++;
+                                               if (q != 0) {
+                                                       if (((int) q->
+                                                            beg & 01) !=
+                                                           0) {
+                                                               printf
+                                                                   ("array %o elt %d odd\n",
+                                                                    i -
+                                                                    ARRAYST,
+                                                                    ct);
+                                                               printf
+                                                                   ("tmps %o p %o\n",
+                                                                    tmps,
+                                                                    p);
+                                                               sdump
+                                                                   ("elt",
+                                                                    q);
+                                                       }
+                                                       redef(q);
+                                               }
+                                       }
+                                       tmps = tmps->next;
+                               } while (tmps != 0);
+                       }
+               }
+       }
+}
+
+void redef(struct blk *p)
+{
+       register offset;
+       register char *newp;
+
+       if ((int) p->beg & 01) {
+               printf("odd ptr %o hdr %o\n", p->beg, p);
+               ospace("redef-bad");
+       }
+       free(p->beg);
+       free(dummy);
+       dummy = malloc(1);
+       if (dummy == NULL)
+               ospace("dummy");
+       newp = realloc(p->beg, (unsigned) (p->last - p->beg));
+       if (newp == NULL)
+               ospace("redef");
+       offset = newp - p->beg;
+       p->beg = newp;
+       p->rd += offset;
+       p->wt += offset;
+       p->last += offset;
+}
+
+void release(struct blk *p)
+{
+       rel++;
+       nbytes -= p->last - p->beg;
+       p->rd = (char *) hfree;
+       hfree = p;
+       free(p->beg);
+}
+
+struct blk *getwd(struct blk *p)
+{
+       register struct wblk *wp;
+
+       wp = (struct wblk *) p;
+       if (wp->rdw == wp->wtw)
+               return (NULL);
+       return (*wp->rdw++);
+}
+
+void putwd(struct blk *p, struct blk *c)
+{
+       register struct wblk *wp;
+
+       wp = (struct wblk *) p;
+       if (wp->wtw == wp->lastw)
+               more(p);
+       *wp->wtw++ = c;
+}
+
+struct blk *lookwd(struct blk *p)
+{
+       register struct wblk *wp;
+
+       wp = (struct wblk *) p;
+       if (wp->rdw == wp->wtw)
+               return (NULL);
+       return (*wp->rdw);
+}
+
+char *nalloc(char *p, unsigned nbytes)
+{
+       char *q, *r;
+       q = r = malloc(nbytes);
+       if (q == 0)
+               return (0);
+       while (nbytes--)
+               *q++ = *p++;
+       return (r);
+}
diff --git a/Applications/V7/cmd/dd.c b/Applications/V7/cmd/dd.c
new file mode 100644 (file)
index 0000000..ebb5add
--- /dev/null
@@ -0,0 +1,551 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#define        BIG     32767
+#define        LCASE   01
+#define        UCASE   02
+#define        SWAB    04
+#define NERR   010
+#define SYNC   020
+int    cflag;
+int    fflag;
+int    skip;
+int    seekn;
+int    count;
+int    files   = 1;
+char   *string;
+char   *ifile;
+char   *ofile;
+char   *ibuf;
+char   *obuf;
+int    ibs     = 512;
+int    obs     = 512;
+int    bs;
+int    cbs;
+int    ibc;
+int    obc;
+int    cbc;
+int    nifr;
+int    nipr;
+int    nofr;
+int    nopr;
+int    ntrunc;
+int    ibf;
+int    obf;
+char   *op;
+int    nspace;
+const char etoa[] = {
+       0000,0001,0002,0003,0234,0011,0206,0177,
+       0227,0215,0216,0013,0014,0015,0016,0017,
+       0020,0021,0022,0023,0235,0205,0010,0207,
+       0030,0031,0222,0217,0034,0035,0036,0037,
+       0200,0201,0202,0203,0204,0012,0027,0033,
+       0210,0211,0212,0213,0214,0005,0006,0007,
+       0220,0221,0026,0223,0224,0225,0226,0004,
+       0230,0231,0232,0233,0024,0025,0236,0032,
+       0040,0240,0241,0242,0243,0244,0245,0246,
+       0247,0250,0133,0056,0074,0050,0053,0041,
+       0046,0251,0252,0253,0254,0255,0256,0257,
+       0260,0261,0135,0044,0052,0051,0073,0136,
+       0055,0057,0262,0263,0264,0265,0266,0267,
+       0270,0271,0174,0054,0045,0137,0076,0077,
+       0272,0273,0274,0275,0276,0277,0300,0301,
+       0302,0140,0072,0043,0100,0047,0075,0042,
+       0303,0141,0142,0143,0144,0145,0146,0147,
+       0150,0151,0304,0305,0306,0307,0310,0311,
+       0312,0152,0153,0154,0155,0156,0157,0160,
+       0161,0162,0313,0314,0315,0316,0317,0320,
+       0321,0176,0163,0164,0165,0166,0167,0170,
+       0171,0172,0322,0323,0324,0325,0326,0327,
+       0330,0331,0332,0333,0334,0335,0336,0337,
+       0340,0341,0342,0343,0344,0345,0346,0347,
+       0173,0101,0102,0103,0104,0105,0106,0107,
+       0110,0111,0350,0351,0352,0353,0354,0355,
+       0175,0112,0113,0114,0115,0116,0117,0120,
+       0121,0122,0356,0357,0360,0361,0362,0363,
+       0134,0237,0123,0124,0125,0126,0127,0130,
+       0131,0132,0364,0365,0366,0367,0370,0371,
+       0060,0061,0062,0063,0064,0065,0066,0067,
+       0070,0071,0372,0373,0374,0375,0376,0377,
+};
+const char atoe[] = {
+       0000,0001,0002,0003,0067,0055,0056,0057,
+       0026,0005,0045,0013,0014,0015,0016,0017,
+       0020,0021,0022,0023,0074,0075,0062,0046,
+       0030,0031,0077,0047,0034,0035,0036,0037,
+       0100,0117,0177,0173,0133,0154,0120,0175,
+       0115,0135,0134,0116,0153,0140,0113,0141,
+       0360,0361,0362,0363,0364,0365,0366,0367,
+       0370,0371,0172,0136,0114,0176,0156,0157,
+       0174,0301,0302,0303,0304,0305,0306,0307,
+       0310,0311,0321,0322,0323,0324,0325,0326,
+       0327,0330,0331,0342,0343,0344,0345,0346,
+       0347,0350,0351,0112,0340,0132,0137,0155,
+       0171,0201,0202,0203,0204,0205,0206,0207,
+       0210,0211,0221,0222,0223,0224,0225,0226,
+       0227,0230,0231,0242,0243,0244,0245,0246,
+       0247,0250,0251,0300,0152,0320,0241,0007,
+       0040,0041,0042,0043,0044,0025,0006,0027,
+       0050,0051,0052,0053,0054,0011,0012,0033,
+       0060,0061,0032,0063,0064,0065,0066,0010,
+       0070,0071,0072,0073,0004,0024,0076,0341,
+       0101,0102,0103,0104,0105,0106,0107,0110,
+       0111,0121,0122,0123,0124,0125,0126,0127,
+       0130,0131,0142,0143,0144,0145,0146,0147,
+       0150,0151,0160,0161,0162,0163,0164,0165,
+       0166,0167,0170,0200,0212,0213,0214,0215,
+       0216,0217,0220,0232,0233,0234,0235,0236,
+       0237,0240,0252,0253,0254,0255,0256,0257,
+       0260,0261,0262,0263,0264,0265,0266,0267,
+       0270,0271,0272,0273,0274,0275,0276,0277,
+       0312,0313,0314,0315,0316,0317,0332,0333,
+       0334,0335,0336,0337,0352,0353,0354,0355,
+       0356,0357,0372,0373,0374,0375,0376,0377,
+};
+const char atoibm[] =
+{
+       0000,0001,0002,0003,0067,0055,0056,0057,
+       0026,0005,0045,0013,0014,0015,0016,0017,
+       0020,0021,0022,0023,0074,0075,0062,0046,
+       0030,0031,0077,0047,0034,0035,0036,0037,
+       0100,0132,0177,0173,0133,0154,0120,0175,
+       0115,0135,0134,0116,0153,0140,0113,0141,
+       0360,0361,0362,0363,0364,0365,0366,0367,
+       0370,0371,0172,0136,0114,0176,0156,0157,
+       0174,0301,0302,0303,0304,0305,0306,0307,
+       0310,0311,0321,0322,0323,0324,0325,0326,
+       0327,0330,0331,0342,0343,0344,0345,0346,
+       0347,0350,0351,0255,0340,0275,0137,0155,
+       0171,0201,0202,0203,0204,0205,0206,0207,
+       0210,0211,0221,0222,0223,0224,0225,0226,
+       0227,0230,0231,0242,0243,0244,0245,0246,
+       0247,0250,0251,0300,0117,0320,0241,0007,
+       0040,0041,0042,0043,0044,0025,0006,0027,
+       0050,0051,0052,0053,0054,0011,0012,0033,
+       0060,0061,0032,0063,0064,0065,0066,0010,
+       0070,0071,0072,0073,0004,0024,0076,0341,
+       0101,0102,0103,0104,0105,0106,0107,0110,
+       0111,0121,0122,0123,0124,0125,0126,0127,
+       0130,0131,0142,0143,0144,0145,0146,0147,
+       0150,0151,0160,0161,0162,0163,0164,0165,
+       0166,0167,0170,0200,0212,0213,0214,0215,
+       0216,0217,0220,0232,0233,0234,0235,0236,
+       0237,0240,0252,0253,0254,0255,0256,0257,
+       0260,0261,0262,0263,0264,0265,0266,0267,
+       0270,0271,0272,0273,0274,0275,0276,0277,
+       0312,0313,0314,0315,0316,0317,0332,0333,
+       0334,0335,0336,0337,0352,0353,0354,0355,
+       0356,0357,0372,0373,0374,0375,0376,0377,
+};
+
+
+void stats(void)
+{
+
+       fprintf(stderr,"%u+%u records in\n", nifr, nipr);
+       fprintf(stderr,"%u+%u records out\n", nofr, nopr);
+       if(ntrunc)
+               fprintf(stderr,"%u truncated records\n", ntrunc);
+}
+
+void term(void)
+{
+
+       stats();
+       exit(0);
+}
+
+void sigterm(int sig)
+{
+       term();
+}
+
+void flsh(void)
+{
+       register c;
+
+       if(obc) {
+               if(obc == obs)
+                       nofr++; else
+                       nopr++;
+               c = write(obf, obuf, obc);
+               if(c != obc) {
+                       perror("write");
+                       term();
+               }
+               obc = 0;
+       }
+}
+
+int match(char *s)
+{
+       register char *cs;
+
+       cs = string;
+       while(*cs++ == *s)
+               if(*s++ == '\0')
+                       goto true;
+       if(*s != '\0')
+               return(0);
+
+true:
+       cs--;
+       string = cs;
+       return(1);
+}
+
+long number(int big)
+{
+       register char *cs;
+       long n;
+
+       cs = string;
+       n = 0;
+       while(*cs >= '0' && *cs <= '9')
+               n = n*10 + *cs++ - '0';
+       for(;;)
+       switch(*cs++) {
+
+       case 'm':
+               n *= 1024L * 1024L;
+               continue;
+       case 'k':
+               n *= 1024;
+               continue;
+
+       case 'w':
+               n *= sizeof(int);
+               continue;
+
+       case 'b':
+               n *= 512;
+               continue;
+
+       case '*':
+       case 'x':
+               string = cs;
+               n *= number(BIG);
+
+       case '\0':
+               if (n>=big || n<0) {
+                       fprintf(stderr, "dd: argument %D out of range\n", n);
+                       exit(1);
+               }
+               return(n);
+       }
+       /* never gets here */
+}
+
+void null(int c)
+{
+
+       *op = c;
+       op++;
+       if(++obc >= obs) {
+               flsh();
+               op = obuf;
+       }
+}
+
+void cnull(int cc)
+{
+       register int c;
+
+       c = cc;
+       if(cflag&UCASE && c>='a' && c<='z')
+               c += 'A'-'a';
+       if(cflag&LCASE && c>='A' && c<='Z')
+               c += 'a'-'A';
+       null(c);
+}
+
+void ascii(int cc)
+{
+       register int c;
+
+       c = etoa[cc] & 0377;
+       if(cbs == 0) {
+               cnull(c);
+               return;
+       }
+       if(c == ' ') {
+               nspace++;
+               goto out;
+       }
+       while(nspace > 0) {
+               null(' ');
+               nspace--;
+       }
+       cnull(c);
+
+out:
+       if(++cbc >= cbs) {
+               null('\n');
+               cbc = 0;
+               nspace = 0;
+       }
+}
+
+void ebcdic(int cc)
+{
+       register int c;
+
+       c = cc;
+       if(cflag&UCASE && c>='a' && c<='z')
+               c += 'A'-'a';
+       if(cflag&LCASE && c>='A' && c<='Z')
+               c += 'a'-'A';
+       c = atoe[c] & 0377;
+       if(cbs == 0) {
+               null(c);
+               return;
+       }
+       if(cc == '\n') {
+               while(cbc < cbs) {
+                       null(atoe[' ']);
+                       cbc++;
+               }
+               cbc = 0;
+               return;
+       }
+       if(cbc == cbs)
+               ntrunc++;
+       cbc++;
+       if(cbc <= cbs)
+               null(c);
+}
+
+void ibm(int cc)
+{
+       register int c;
+
+       c = cc;
+       if(cflag&UCASE && c>='a' && c<='z')
+               c += 'A'-'a';
+       if(cflag&LCASE && c>='A' && c<='Z')
+               c += 'a'-'A';
+       c = atoibm[c] & 0377;
+       if(cbs == 0) {
+               null(c);
+               return;
+       }
+       if(cc == '\n') {
+               while(cbc < cbs) {
+                       null(atoibm[' ']);
+                       cbc++;
+               }
+               cbc = 0;
+               return;
+       }
+       if(cbc == cbs)
+               ntrunc++;
+       cbc++;
+       if(cbc <= cbs)
+               null(c);
+}
+
+
+
+int main(int argc, char *argv[])
+{
+       void (*conv)(int);
+       register char *ip;
+       register int c;
+       int a;
+
+       conv = null;
+       for(c=1; c<argc; c++) {
+               string = argv[c];
+               if(match("ibs=")) {
+                       ibs = number(BIG);
+                       continue;
+               }
+               if(match("obs=")) {
+                       obs = number(BIG);
+                       continue;
+               }
+               if(match("cbs=")) {
+                       cbs = number(BIG);
+                       continue;
+               }
+               if (match("bs=")) {
+                       bs = number(BIG);
+                       continue;
+               }
+               if(match("if=")) {
+                       ifile = string;
+                       continue;
+               }
+               if(match("of=")) {
+                       ofile = string;
+                       continue;
+               }
+               if(match("skip=")) {
+                       skip = number(BIG);
+                       continue;
+               }
+               if(match("seek=")) {
+                       seekn = number(BIG);
+                       continue;
+               }
+               if(match("count=")) {
+                       count = number(BIG);
+                       continue;
+               }
+               if(match("files=")) {
+                       files = number(BIG);
+                       continue;
+               }
+               if(match("conv=")) {
+               cloop:
+                       if(match(","))
+                               goto cloop;
+                       if(*string == '\0')
+                               continue;
+                       if(match("ebcdic")) {
+                               conv = ebcdic;
+                               goto cloop;
+                       }
+                       if(match("ibm")) {
+                               conv = ibm;
+                               goto cloop;
+                       }
+                       if(match("ascii")) {
+                               conv = ascii;
+                               goto cloop;
+                       }
+                       if(match("lcase")) {
+                               cflag |= LCASE;
+                               goto cloop;
+                       }
+                       if(match("ucase")) {
+                               cflag |= UCASE;
+                               goto cloop;
+                       }
+                       if(match("swab")) {
+                               cflag |= SWAB;
+                               goto cloop;
+                       }
+                       if(match("noerror")) {
+                               cflag |= NERR;
+                               goto cloop;
+                       }
+                       if(match("sync")) {
+                               cflag |= SYNC;
+                               goto cloop;
+                       }
+               }
+               fprintf(stderr,"bad arg: %s\n", string);
+               exit(0);
+       }
+       if(conv == null && cflag&(LCASE|UCASE))
+               conv = cnull;
+       if (ifile)
+               ibf = open(ifile, 0);
+       else
+               ibf = dup(0);
+       if(ibf < 0) {
+               fprintf(stderr,"cannot open: %s\n", ifile);
+               exit(0);
+       }
+       if (ofile)
+               obf = creat(ofile, 0666);
+       else
+               obf = dup(1);
+       if(obf < 0) {
+               fprintf(stderr,"cannot create: %s\n", ofile);
+               exit(0);
+       }
+       if (bs) {
+               ibs = obs = bs;
+               if (conv == null)
+                       fflag++;
+       }
+       if(ibs == 0 || obs == 0) {
+               fprintf(stderr,"counts: cannot be zero\n");
+               exit(0);
+       }
+       ibuf = sbrk(ibs);
+       if (fflag)
+               obuf = ibuf;
+       else
+               obuf = sbrk(obs);
+       sbrk(64);       /* For good measure */
+       if(ibuf == (char *)-1 || obuf == (char *)-1) {
+               fprintf(stderr, "not enough memory\n");
+               exit(0);
+       }
+       ibc = 0;
+       obc = 0;
+       cbc = 0;
+       op = obuf;
+
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+               signal(SIGINT, sigterm);
+       while(skip) {
+               read(ibf, ibuf, ibs);
+               skip--;
+       }
+       while(seekn) {
+               lseek(obf, (long)obs, 1);
+               seekn--;
+       }
+
+loop:
+       if(ibc-- == 0) {
+               ibc = 0;
+               if(count==0 || nifr+nipr!=count) {
+                       if(cflag&(NERR|SYNC))
+                       for(ip=ibuf+ibs; ip>ibuf;)
+                               *--ip = 0;
+                       ibc = read(ibf, ibuf, ibs);
+               }
+               if(ibc == -1) {
+                       perror("read");
+                       if((cflag&NERR) == 0) {
+                               flsh();
+                               term();
+                       }
+                       ibc = 0;
+                       for(c=0; c<ibs; c++)
+                               if(ibuf[c] != 0)
+                                       ibc = c;
+                       stats();
+               }
+               if(ibc == 0 && --files<=0) {
+                       flsh();
+                       term();
+               }
+               if(ibc != ibs) {
+                       nipr++;
+                       if(cflag&SYNC)
+                               ibc = ibs;
+               } else
+                       nifr++;
+               ip = ibuf;
+               c = (ibc>>1) & ~1;
+               if(cflag&SWAB && c)
+               do {
+                       a = *ip++;
+                       ip[-1] = *ip;
+                       *ip++ = a;
+               } while(--c);
+               ip = ibuf;
+               if (fflag) {
+                       obc = ibc;
+                       flsh();
+                       ibc = 0;
+               }
+               goto loop;
+       }
+       c = 0;
+       c |= *ip++;
+       c &= 0377;
+       (*conv)(c);
+       goto loop;
+}
diff --git a/Applications/V7/cmd/deroff.c b/Applications/V7/cmd/deroff.c
new file mode 100644 (file)
index 0000000..cb6e56d
--- /dev/null
@@ -0,0 +1,466 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+char *xxxvers = "\nDeroff Version 1.02fuzix    18th March 2015\n";
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Deroff command -- strip troff, eqn, and Tbl sequences from
+a file.  Has one flag argument, -w, to cause output one word per line
+rather than in the original format.
+Deroff follows .so and .nx commands, removes contents of macro
+definitions, equations (both .EQ ... .EN and $...$),
+Tbl command sequences, and Troff backslash constructions.
+
+All input is through the C macro; the most recently read character is in c.
+*/
+
+#define C ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) )
+#define C1 ( (c=getc(infile)) == EOF ? eof() :  c)
+#define SKIP while(C != '\n')
+
+#define YES 1
+#define NO 0
+
+#define NOCHAR -2
+#define SPECIAL 0
+#define APOS 1
+#define DIGIT 2
+#define LETTER 3
+
+int wordflag = NO;
+int inmacro = NO;
+int intable = NO;
+
+char chars[128];               /* SPECIAL, APOS, DIGIT, or LETTER */
+
+char line[512];
+char *lp;
+
+int c;
+int ldelim = NOCHAR;
+int rdelim = NOCHAR;
+
+
+int argc;
+char **argv;
+
+char fname[50];
+FILE *files[15];
+FILE **filesp;
+FILE *infile;
+
+
+extern int eof(void);
+extern void backsl(void);
+
+
+void fatal(const char *s, const char *p)
+{
+       fprintf(stderr, "Deroff: ");
+       fprintf(stderr, s, p);
+       exit(1);
+}
+
+FILE *opn(const char *p)
+{
+       FILE *fd;
+
+       if (p[0] == '-' && p[1] == '\0')
+               fd = stdin;
+       else if ((fd = fopen(p, "r")) == NULL)
+               fatal("Cannot open file %s\n", p);
+
+       return (fd);
+}
+
+
+int skeqn(void)
+{
+       while ((c = getc(infile)) != rdelim)
+               if (c == EOF)
+                       c = eof();
+               else if (c == '"')
+                       while ((c = getc(infile)) != '"')
+                               if (c == EOF)
+                                       c = eof();
+                               else if (c == '\\')
+                                       if ((c = getc(infile)) == EOF)
+                                               c = eof();
+       return (c = ' ');
+}
+
+int eof(void)
+{
+       if (infile != stdin)
+               fclose(infile);
+       if (filesp > files)
+               infile = *--filesp;
+       else if (argc > 0) {
+               infile = opn(argv[0]);
+               --argc;
+               ++argv;
+       } else
+               exit(0);
+
+       return (C);
+}
+
+
+
+char *copys(char *s)
+{
+       register char *t, *t0;
+
+       if ((t0 = t = calloc(strlen(s) + 1, sizeof(*t))) == NULL)
+               fatal("Cannot allocate memory", (char *) NULL);
+
+       while (*t++ = *s++);
+       return (t0);
+}
+
+void getfname(void)
+{
+       register char *p;
+       struct chain {
+               struct chain *nextp;
+               char *datap;
+       } *chainblock;
+       register struct chain *q;
+       static struct chain *namechain = NULL;
+
+       while (C == ' ');
+
+       for (p = fname;
+            (*p = c) != '\n' && c != ' ' && c != '\t' && c != '\\'; ++p)
+               C;
+       *p = '\0';
+       while (c != '\n')
+               C;
+
+/* see if this name has already been used */
+
+       for (q = namechain; q; q = q->nextp)
+               if (!strcmp(fname, q->datap)) {
+                       fname[0] = '\0';
+                       return;
+               }
+
+       q = (struct chain *) calloc(1, sizeof(*chainblock));
+       q->nextp = namechain;
+       q->datap = copys(fname);
+       namechain = q;
+}
+
+void putmac(char *s)
+{
+       register char *t;
+
+       while (*s) {
+               while (*s == ' ' || *s == '\t')
+                       putchar(*s++);
+               for (t = s; *t != ' ' && *t != '\t' && *t != '\0'; ++t);
+               if (t > s + 2 && chars[s[0]] == LETTER
+                   && chars[s[1]] == LETTER)
+                       while (s < t)
+                               putchar(*s++);
+               else
+                       s = t;
+       }
+       putchar('\n');
+}
+
+
+
+void putwords(int macline)
+{                              /* break into words for -w option */
+       register char *p, *p1;
+       int i, nlet;
+
+
+       for (p1 = line;;) {
+               /* skip initial specials ampersands and apostrophes */
+               while (chars[*p1] < DIGIT)
+                       if (*p1++ == '\0')
+                               return;
+               nlet = 0;
+               for (p = p1; (i = chars[*p]) != SPECIAL; ++p)
+                       if (i == LETTER)
+                               ++nlet;
+
+               if ((!macline && nlet > 1)      /* MDM definition of word */
+                   ||(macline && nlet > 2 && chars[p1[0]] == LETTER
+                      && chars[p1[1]] == LETTER)) {
+                       /* delete trailing ampersands and apostrophes */
+                       while (p[-1] == '\'' || p[-1] == '&')
+                               --p;
+                       while (p1 < p)
+                               putchar(*p1++);
+                       putchar('\n');
+               } else
+                       p1 = p;
+       }
+}
+
+
+void regline(int macline)
+{
+       line[0] = c;
+       lp = line;
+       for (;;) {
+               if (c == '\\') {
+                       *lp = ' ';
+                       backsl();
+               }
+               if (c == '\n')
+                       break;
+               if (intable && c == 'T') {
+                       *++lp = C;
+                       if (c == '{' || c == '}') {
+                               lp[-1] = ' ';
+                               *lp = C;
+                       }
+               } else
+                       *++lp = C;
+       }
+
+       *lp = '\0';
+
+       if (line[0] != '\0')
+               if (wordflag)
+                       putwords(macline);
+               else if (macline)
+                       putmac(line);
+               else
+                       puts(line);
+}
+
+
+
+
+
+
+void macro(void)
+{
+/*
+do { SKIP; }
+       while(C!='.' || C!='.' || C=='.');      /* look for  .. */
+       SKIP;
+       inmacro = YES;
+}
+
+
+
+
+void tbl(void)
+{
+       while (C != '.');
+       SKIP;
+       intable = YES;
+}
+
+
+void eqn(void)
+{
+       register int c1, c2;
+
+       SKIP;
+
+       for (;;) {
+               if (C == '.' || c == '\'') {
+                       while (C == ' ' || c == '\t');
+                       if (c == 'E' && C == 'N') {
+                               SKIP;
+                               return;
+                       }
+               } else if (c == 'd') {  /* look for delim */
+                       if (C == 'e' && C == 'l')
+                               if (C == 'i' && C == 'm') {
+                                       while (C1 == ' ');
+                                       if ((c1 = c) == '\n'
+                                           || (c2 = C1) == '\n'
+                                           || (c1 == 'o' && c2 == 'f'
+                                               && C1 == 'f')) {
+                                               ldelim = NOCHAR;
+                                               rdelim = NOCHAR;
+                                       } else {
+                                               ldelim = c1;
+                                               rdelim = c2;
+                                       }
+                               }
+               }
+
+               if (c != '\n')
+                       SKIP;
+       }
+}
+
+void backsl(void)
+{                              /* skip over a complete backslash construction */
+       int bdelim;
+
+      sw:switch (C) {
+       case '"':
+               SKIP;
+               return;
+       case 's':
+               if (C == '\\')
+                       backsl();
+               else {
+                       while (C >= '0' && c <= '9');
+                       ungetc(c, infile);
+                       c = '0';
+               }
+               --lp;
+               return;
+
+       case 'f':
+       case 'n':
+       case '*':
+               if (C != '(')
+                       return;
+
+       case '(':
+               if (C != '\n')
+                       C;
+               return;
+
+       case '$':
+               C;              /* discard argument number */
+               return;
+
+       case 'b':
+       case 'x':
+       case 'v':
+       case 'h':
+       case 'w':
+       case 'o':
+       case 'l':
+       case 'L':
+               if ((bdelim = C) == '\n')
+                       return;
+               while (C != '\n' && c != bdelim)
+                       if (c == '\\')
+                               backsl();
+               return;
+
+       case '\\':
+               if (inmacro)
+                       goto sw;
+       default:
+               return;
+       }
+}
+
+void comline(void)
+{
+       register int c1, c2;
+
+       while (C == ' ' || c == '\t');
+       if ((c1 = c) == '\n')
+               return;
+       c2 = C;
+       if (c1 == '.' && c2 != '.')
+               inmacro = NO;
+       if (c2 == '\n')
+               return;
+
+       if (c1 == 'E' && c2 == 'Q' && filesp == files)
+               eqn();
+       else if (c1 == 'T' && (c2 == 'S' || c2 == 'C' || c2 == '&')
+                && filesp == files)
+               tbl();
+       else if (c1 == 'T' && c2 == 'E')
+               intable = NO;
+       else if (!inmacro && c1 == 'd' && c2 == 'e')
+               macro();
+       else if (!inmacro && c1 == 'i' && c2 == 'g')
+               macro();
+       else if (!inmacro && c1 == 'a' && c2 == 'm')
+               macro();
+       else if (c1 == 's' && c2 == 'o') {
+               getfname();
+               if (fname[0])
+                       infile = *++filesp = opn(fname);
+       } else if (c1 == 'n' && c2 == 'x') {
+               getfname();
+               if (fname[0] == '\0')
+                       exit(0);
+               if (infile != stdin)
+                       fclose(infile);
+               infile = *filesp = opn(fname);
+       } else if (c1 == 'h' && c2 == 'w') {
+               SKIP;
+       } else {
+               if (c1 == '.' && c2 == '.')
+                       while (C == '.');
+               ++inmacro;
+               regline(YES);
+               --inmacro;
+       }
+}
+
+
+void work(void)
+{
+
+       for (;;) {
+               if (C == '.' || c == '\'')
+                       comline();
+               else
+                       regline(NO);
+       }
+}
+
+
+
+
+int main(int ac, const char *av[])
+{
+       register int i;
+       register char *p;
+       static char onechar[2] = "X";
+
+       argc = ac - 1;
+       argv = av + 1;
+
+       while (argc > 0 && argv[0][0] == '-' && argv[0][1] != '\0') {
+               for (p = argv[0] + 1; *p; ++p)
+                       switch (*p) {
+                       case 'w':
+                               wordflag = YES;
+                               break;
+                       default:
+                               onechar[0] = *p;
+                               fatal("Invalid flag %s\n", onechar);
+                       }
+               --argc;
+               ++argv;
+       }
+
+       if (argc == 0)
+               infile = stdin;
+       else {
+               infile = opn(argv[0]);
+               --argc;
+               ++argv;
+       }
+
+       files[0] = infile;
+       filesp = &files[0];
+
+       for (i = 'a'; i <= 'z'; ++i)
+               chars[i] = LETTER;
+       for (i = 'A'; i <= 'Z'; ++i)
+               chars[i] = LETTER;
+       for (i = '0'; i <= '9'; ++i)
+               chars[i] = DIGIT;
+       chars['\''] = APOS;
+       chars['&'] = APOS;
+
+       work();
+}
diff --git a/Applications/V7/cmd/diff.c b/Applications/V7/cmd/diff.c
new file mode 100644 (file)
index 0000000..d1e890b
--- /dev/null
@@ -0,0 +1,645 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+/*     diff - differential file comparison
+*
+*      Uses an algorithm due to Harold Stone, which finds
+*      a pair of longest identical subsequences in the two
+*      files.
+*
+*      The major goal is to generate the match vector J.
+*      J[i] is the index of the line in file1 corresponding
+*      to line i file0. J[i] = 0 if there is no
+*      such line in file1.
+*
+*      Lines are hashed so as to work in core. All potential
+*      matches are located by sorting the lines of each file
+*      on the hash (called value\b\b\b\b\b_____). In particular, this
+*      collects the equivalence classes in file1 together.
+*      Subroutine equiv\b\b\b\b____  replaces the value of each line in
+*      file0 by the index of the first element of its 
+*      matching equivalence in (the reordered) file1.
+*      To save space equiv\b\b\b\b\b_____ squeezes file1 into a single
+*      array member\b\b\b\b\b\b______ in which the equivalence classes
+*      are simply concatenated, except that their first
+*      members are flagged by changing sign.
+*
+*      Next the indices that point into member\b\b\b\b\b\b______ are unsorted\b\b\b\b\b\b\b\b_______   into
+*      array class\b\b\b\b\b_____ according to the original order of file0.
+*
+*      The cleverness lies in routine stone\b\b\b\b\b______. This marches
+*      through the lines of file0, developing a vector klist\b\b\b\b\b_____
+*      of "k-candidates". At step i a k-candidate is a matched
+*      pair of lines x,y (x in file0 y in file1) such that
+*      there is a common subsequence of lenght k
+*      between the first i lines of file0 and the first y 
+*      lines of file1, but there is no such subsequence for
+*      any smaller y. x is the earliest possible mate to y
+*      that occurs in such a subsequence.
+*
+*      Whenever any of the members of the equivalence class of
+*      lines in file1 matable to a line in file0 has serial number 
+*      less than the y of some k-candidate, that k-candidate 
+*      with the smallest such y is replaced. The new 
+*      k-candidate is chained (via pred\b\b\b\b____) to the current
+*      k-1 candidate so that the actual subsequence can
+*      be recovered. When a member has serial number greater
+*      that the y of all k-candidates, the klist is extended.
+*      At the end, the longest subsequence is pulled out
+*      and placed in the array J by unravel\b\b\b\b\b\b\b_______.
+*
+*      With J in hand, the matches there recorded are
+*      check\b\b\b\b\b_____ed against reality to assure that no spurious
+*      matches have crept in due to hashing. If they have,
+*      they are broken, and "jackpot " is recorded--a harmless
+*      matter except that a true match for a spuriously
+*      mated line may now be unnecessarily reported as a change.
+*
+*      Much of the complexity of the program comes simply
+*      from trying to minimize core utilization and
+*      maximize the range of doable problems by dynamically
+*      allocating what is needed and reusing what is not.
+*      The core requirements for problems larger than somewhat
+*      are (in words) 2*length(file0) + length(file1) +
+*      3*(number of k-candidates installed),  typically about
+*      6n words for files of length n. 
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#define        prints(s)       fputs(s,stdout)
+
+#define HALFLONG 16
+#define low(x) (x&((1L<<HALFLONG)-1))
+#define high(x)        (x>>HALFLONG)
+FILE *input[2];
+
+struct cand {
+       int x;
+       int y;
+       int pred;
+} cand;
+struct line {
+       int serial;
+       int value;
+} *file[2], line;
+int len[2];
+struct line *sfile[2];         /*shortened by pruning common prefix and suffix */
+int slen[2];
+int pref, suff;                        /*length of prefix and suffix */
+int *class;                    /*will be overlaid on file[0] */
+int *member;                   /*will be overlaid on file[1] */
+int *klist;                    /*will be overlaid on file[0] after class */
+struct cand *clist;            /* merely a free storage pot for candidates */
+int clen = 0;
+int *J;                                /*will be overlaid on class */
+long *ixold;                   /*will be overlaid on klist */
+long *ixnew;                   /*will be overlaid on file[1] */
+int opt;                       /* -1,0,1 = -e,normal,-f */
+int status = 2;
+int anychange = 0;
+char *empty = "";
+int bflag;
+
+char *tempfile;                        /*used when comparing against std input */
+char *dummy;                   /*used in resetting storage search ptr */
+
+void done(void)
+{
+       unlink(tempfile);
+       exit(status);
+}
+
+void sdone(int sig)
+{
+       done();
+}
+
+void mesg(char *s, char *t)
+{
+       fprintf(stderr, "diff: %s%s\n", s, t);
+}
+
+void noroom(void)
+{
+       mesg("files too big, try -h\n", empty);
+       done();
+}
+
+char *talloc(size_t n)
+{
+       register char *p;
+       p = malloc(n);
+       if (p != NULL)
+               return (p);
+       noroom();
+}
+
+char *ralloc(char *p, size_t n)
+{
+       char *q = realloc(p, n);
+       if (q == NULL)
+               noroom();
+       return (q);
+}
+
+void sort(struct line *a, int n)
+{                              /*shellsort CACM #201 */
+       struct line w;
+       register int j, m;
+       struct line *ai;
+       register struct line *aim;
+       int k;
+       for (j = 1; j <= n; j *= 2)
+               m = 2 * j - 1;
+       for (m /= 2; m != 0; m /= 2) {
+               k = n - m;
+               for (j = 1; j <= k; j++) {
+                       for (ai = &a[j]; ai > a; ai -= m) {
+                               aim = &ai[m];
+                               if (aim < ai)
+                                       break;  /*wraparound */
+                               if (aim->value > ai[0].value ||
+                                   aim->value == ai[0].value &&
+                                   aim->serial > ai[0].serial)
+                                       break;
+                               w.value = ai[0].value;
+                               ai[0].value = aim->value;
+                               aim->value = w.value;
+                               w.serial = ai[0].serial;
+                               ai[0].serial = aim->serial;
+                               aim->serial = w.serial;
+                       }
+               }
+       }
+}
+
+void unsort(struct line *f, int l, int *b)
+{
+       register int *a;
+       register int i;
+       a = (int *) talloc((l + 1) * sizeof(int));
+       for (i = 1; i <= l; i++)
+               a[f[i].serial] = f[i].value;
+       for (i = 1; i <= l; i++)
+               b[i] = a[i];
+       free((char *) a);
+}
+
+int skipline(int f)
+{
+       register i;
+       for (i = 1; getc(input[f]) != '\n'; i++);
+       return (i);
+}
+
+void filename(char **pa1, char **pa2)
+{
+       register char *a1, *b1, *a2;
+       char buf[512];
+       struct stat stbuf;
+       int i, f;
+       a1 = *pa1;
+       a2 = *pa2;
+       if (stat(a1, &stbuf) != -1
+           && ((stbuf.st_mode & S_IFMT) == S_IFDIR)) {
+               b1 = *pa1 = malloc(100);
+               while (*b1++ = *a1++);
+               b1[-1] = '/';
+               a1 = b1;
+               while (*a1++ = *a2++)
+                       if (*a2 && *a2 != '/' && a2[-1] == '/')
+                               a1 = b1;
+       } else if (a1[0] == '-' && a1[1] == 0 && tempfile == 0) {
+               signal(SIGHUP, sdone);
+               signal(SIGINT, sdone);
+               signal(SIGPIPE, sdone);
+               signal(SIGTERM, sdone);
+               *pa1 = tempfile = tmpnam("diffXXXXX");
+               if ((f =
+                    open(tempfile, O_CREAT | O_EXCL | O_WRONLY,
+                         0600)) < 0) {
+                       mesg("cannot create ", tempfile);
+                       done();
+               }
+               while ((i = read(0, buf, 512)) > 0)
+                       write(f, buf, i);
+               close(f);
+       }
+}
+
+/* hashing has the effect of
+ * arranging line in 7-bit bytes and then
+ * summing 1-s complement in 16-bit hunks 
+*/
+
+int readhash(FILE * f)
+{
+       long sum;
+       register unsigned shift;
+       register space;
+       register t;
+       sum = 1;
+       space = 0;
+       if (!bflag)
+               for (shift = 0; (t = getc(f)) != '\n'; shift += 7) {
+                       if (t == -1)
+                               return (0);
+                       sum += (long) t << (shift %= HALFLONG);
+       } else
+               for (shift = 0;;) {
+                       switch (t = getc(f)) {
+                       case -1:
+                               return (0);
+                       case '\t':
+                       case ' ':
+                               space++;
+                               continue;
+                       default:
+                               if (space) {
+                                       shift += 7;
+                                       space = 0;
+                               }
+                               sum += (long) t << (shift %= HALFLONG);
+                               shift += 7;
+                               continue;
+                       case '\n':
+                               break;
+                       }
+                       break;
+               }
+       sum = low(sum) + high(sum);
+       return ((short) low(sum) + (short) high(sum));
+}
+
+void prepare(int i, char *arg)
+{
+       register struct line *p;
+       register j, h;
+       if ((input[i] = fopen(arg, "r")) == NULL) {
+               mesg("cannot open ", arg);
+               done();
+       }
+       p = (struct line *) talloc(3 * sizeof(line));
+       for (j = 0; h = readhash(input[i]);) {
+               p = (struct line *) ralloc((char *) p,
+                                          (++j + 3) * sizeof(line));
+               p[j].value = h;
+       }
+       len[i] = j;
+       file[i] = p;
+       fclose(input[i]);
+}
+
+void prune(void)
+{
+       register i, j;
+       for (pref = 0; pref < len[0] && pref < len[1] &&
+            file[0][pref + 1].value == file[1][pref + 1].value; pref++);
+       for (suff = 0; suff < len[0] - pref && suff < len[1] - pref &&
+            file[0][len[0] - suff].value == file[1][len[1] - suff].value;
+            suff++);
+       for (j = 0; j < 2; j++) {
+               sfile[j] = file[j] + pref;
+               slen[j] = len[j] - pref - suff;
+               for (i = 0; i <= slen[j]; i++)
+                       sfile[j][i].serial = i;
+       }
+}
+
+void equiv(struct line *a, int n, struct line *b, int m, int *c)
+{
+       register int i, j;
+       i = j = 1;
+       while (i <= n && j <= m) {
+               if (a[i].value < b[j].value)
+                       a[i++].value = 0;
+               else if (a[i].value == b[j].value)
+                       a[i++].value = j;
+               else
+                       j++;
+       }
+       while (i <= n)
+               a[i++].value = 0;
+       b[m + 1].value = 0;
+       j = 0;
+       while (++j <= m) {
+               c[j] = -b[j].serial;
+               while (b[j + 1].value == b[j].value) {
+                       j++;
+                       c[j] = b[j].serial;
+               }
+       }
+       c[j] = -1;
+}
+
+int newcand(int x, int y, int pred)
+{
+       register struct cand *q;
+       clist =
+           (struct cand *) ralloc((char *) clist, ++clen * sizeof(cand));
+       q = clist + clen - 1;
+       q->x = x;
+       q->y = y;
+       q->pred = pred;
+       return (clen - 1);
+}
+
+int search(int *c, int k, int y)
+{
+       register int i, j, l;
+       int t;
+       if (clist[c[k]].y < y)  /*quick look for typical case */
+               return (k + 1);
+       i = 0;
+       j = k + 1;
+       while ((l = (i + j) / 2) > i) {
+               t = clist[c[l]].y;
+               if (t > y)
+                       j = l;
+               else if (t < y)
+                       i = l;
+               else
+                       return (l);
+       }
+       return (l + 1);
+}
+
+void unravel(int p)
+{
+       register int i;
+       register struct cand *q;
+       for (i = 0; i <= len[0]; i++)
+               J[i] = i <= pref ? i :
+                   i > len[0] - suff ? i + len[1] - len[0] : 0;
+       for (q = clist + p; q->y != 0; q = clist + q->pred)
+               J[q->x + pref] = q->y + pref;
+}
+
+
+int stone(int *a, int n, int *b, int *c)
+{
+       register int i, k, y;
+       int j, l;
+       int oldc, tc;
+       int oldl;
+       k = 0;
+       c[0] = newcand(0, 0, 0);
+       for (i = 1; i <= n; i++) {
+               j = a[i];
+               if (j == 0)
+                       continue;
+               y = -b[j];
+               oldl = 0;
+               oldc = c[0];
+               do {
+                       if (y <= clist[oldc].y)
+                               continue;
+                       l = search(c, k, y);
+                       if (l != oldl + 1)
+                               oldc = c[l - 1];
+                       if (l <= k) {
+                               if (clist[c[l]].y <= y)
+                                       continue;
+                               tc = c[l];
+                               c[l] = newcand(i, y, oldc);
+                               oldc = tc;
+                               oldl = l;
+                       } else {
+                               c[l] = newcand(i, y, oldc);
+                               k++;
+                               break;
+                       }
+               } while ((y = b[++j]) > 0);
+       }
+       return (k);
+}
+
+/* check does double duty:
+1.  ferret out any fortuitous correspondences due
+to confounding by hashing (which result in "jackpot")
+2.  collect random access indexes to the two files */
+
+void check(const char *argv[])
+{
+       register int i, j;
+       int jackpot;
+       long ctold, ctnew;
+       char c, d;
+       input[0] = fopen(argv[1], "r");
+       input[1] = fopen(argv[2], "r");
+       j = 1;
+       ixold[0] = ixnew[0] = 0;
+       jackpot = 0;
+       ctold = ctnew = 0;
+       for (i = 1; i <= len[0]; i++) {
+               if (J[i] == 0) {
+                       ixold[i] = ctold += skipline(0);
+                       continue;
+               }
+               while (j < J[i]) {
+                       ixnew[j] = ctnew += skipline(1);
+                       j++;
+               }
+               for (;;) {
+                       c = getc(input[0]);
+                       d = getc(input[1]);
+                       ctold++;
+                       ctnew++;
+                       if (bflag && isspace(c) && isspace(d)) {
+                               do {
+                                       if (c == '\n')
+                                               break;
+                                       ctold++;
+                               } while (isspace(c = getc(input[0])));
+                               do {
+                                       if (d == '\n')
+                                               break;
+                                       ctnew++;
+                               } while (isspace(d = getc(input[1])));
+                       }
+                       if (c != d) {
+                               jackpot++;
+                               J[i] = 0;
+                               if (c != '\n')
+                                       ctold += skipline(0);
+                               if (d != '\n')
+                                       ctnew += skipline(1);
+                               break;
+                       }
+                       if (c == '\n')
+                               break;
+               }
+               ixold[i] = ctold;
+               ixnew[j] = ctnew;
+               j++;
+       }
+       for (; j <= len[1]; j++) {
+               ixnew[j] = ctnew += skipline(1);
+       }
+       fclose(input[0]);
+       fclose(input[1]);
+/*
+       if(jackpot)
+               mesg("jackpot",empty);
+*/
+}
+
+void range(int a, int b, char *separator)
+{
+       printf("%d", a > b ? b : a);
+       if (a < b) {
+               printf("%s%d", separator, b);
+       }
+}
+
+int fetch(long *f, int a, int b, FILE * lb, char *s)
+{
+       register int i, j;
+       register int nc;
+       for (i = a; i <= b; i++) {
+               fseek(lb, f[i - 1], 0);
+               nc = f[i] - f[i - 1];
+               prints(s);
+               for (j = 0; j < nc; j++)
+                       putchar(getc(lb));
+       }
+}
+
+void change(int a, int b, int c, int d)
+{
+       if (a > b && c > d)
+               return;
+       anychange = 1;
+       if (opt != 1) {
+               range(a, b, ",");
+               putchar(a > b ? 'a' : c > d ? 'd' : 'c');
+               if (opt != -1)
+                       range(c, d, ",");
+       } else {
+               putchar(a > b ? 'a' : c > d ? 'd' : 'c');
+               range(a, b, " ");
+       }
+       putchar('\n');
+       if (opt == 0) {
+               fetch(ixold, a, b, input[0], "< ");
+               if (a <= b && c <= d)
+                       prints("---\n");
+       }
+       fetch(ixnew, c, d, input[1], opt == 0 ? "> " : empty);
+       if (opt != 0 && c <= d)
+               prints(".\n");
+}
+
+void output(const char *argv[])
+{
+       int m;
+       register int i0, i1, j1;
+       int j0;
+       input[0] = fopen(argv[1], "r");
+       input[1] = fopen(argv[2], "r");
+       m = len[0];
+       J[0] = 0;
+       J[m + 1] = len[1] + 1;
+       if (opt != -1)
+               for (i0 = 1; i0 <= m; i0 = i1 + 1) {
+                       while (i0 <= m && J[i0] == J[i0 - 1] + 1)
+                               i0++;
+                       j0 = J[i0 - 1] + 1;
+                       i1 = i0 - 1;
+                       while (i1 < m && J[i1 + 1] == 0)
+                               i1++;
+                       j1 = J[i1 + 1] - 1;
+                       J[i1] = j1;
+                       change(i0, i1, j0, j1);
+       } else
+               for (i0 = m; i0 >= 1; i0 = i1 - 1) {
+                       while (i0 >= 1 && J[i0] == J[i0 + 1] - 1
+                              && J[i0] != 0)
+                               i0--;
+                       j0 = J[i0 + 1] - 1;
+                       i1 = i0 + 1;
+                       while (i1 > 1 && J[i1 - 1] == 0)
+                               i1--;
+                       j1 = J[i1 - 1] + 1;
+                       J[i1] = j1;
+                       change(i1, i0, j1, j0);
+               }
+       if (m == 0)
+               change(1, 0, 1, len[1]);
+}
+
+int main(int argc, const char *argv[])
+{
+       register int k;
+       const char **args;
+
+       args = argv;
+       if (argc > 3 && *argv[1] == '-') {
+               argc--;
+               argv++;
+               for (k = 1; argv[0][k]; k++) {
+                       switch (argv[0][k]) {
+                       case 'e':
+                               opt = -1;
+                               break;
+                       case 'f':
+                               opt = 1;
+                               break;
+                       case 'b':
+                               bflag = 1;
+                               break;
+                       case 'h':
+                               execv("/usr/lib/diffh", args);
+                               mesg("cannot find diffh", empty);
+                               done();
+                       }
+               }
+       }
+       if (argc != 3) {
+               mesg("arg count", empty);
+               done();
+       }
+
+       filename(&argv[1], &argv[2]);
+       filename(&argv[2], &argv[1]);
+       prepare(0, argv[1]);
+       prepare(1, argv[2]);
+       prune();
+       sort(sfile[0], slen[0]);
+       sort(sfile[1], slen[1]);
+
+       member = (int *) file[1];
+       equiv(sfile[0], slen[0], sfile[1], slen[1], member);
+       member =
+           (int *) ralloc((char *) member, (slen[1] + 2) * sizeof(int));
+
+       class = (int *) file[0];
+       unsort(sfile[0], slen[0], class);
+       class =
+           (int *) ralloc((char *) class, (slen[0] + 2) * sizeof(int));
+
+       klist = (int *) talloc((slen[0] + 2) * sizeof(int));
+       clist = (struct cand *) talloc(sizeof(cand));
+       k = stone(class, slen[0], member, klist);
+       free((char *) member);
+       free((char *) class);
+
+       J = (int *) talloc((len[0] + 2) * sizeof(int));
+       unravel(klist[k]);
+       free((char *) clist);
+       free((char *) klist);
+
+       ixold = (long *) talloc((len[0] + 2) * sizeof(long));
+       ixnew = (long *) talloc((len[1] + 2) * sizeof(long));
+       check(argv);
+       output(argv);
+       status = anychange;
+       done();
+}
diff --git a/Applications/V7/cmd/diff3.c b/Applications/V7/cmd/diff3.c
new file mode 100644 (file)
index 0000000..44d8a03
--- /dev/null
@@ -0,0 +1,421 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* diff3 - 3-way differential file comparison*/
+
+/* diff3 [-e] d13 d23 f1 f2 f3 
+ *
+ * d13 = diff report on f1 vs f3
+ * d23 = diff report on f2 vs f3
+ * f1, f2, f3 the 3 files
+*/
+
+struct range {
+       int from, to;
+};
+       /* from is first in range of changed lines
+        * to is last+1
+        * from=to=line after point of insertion
+        * for added lines
+        */
+struct diff {
+       struct range old, new;
+};
+
+#define NC 200
+/* de is used to gather editing scripts,
+ * that are later spewed out in reverse order.
+ * its first element must be all zero
+ * the "new" component of de contains line positions
+ * or byte positions depending on when you look(!?)
+*/
+struct diff d13[NC];
+struct diff d23[NC];
+struct diff de[NC];
+char line[256];
+FILE *fp[3];
+int linct[3] = { 0, 0, 0 };
+
+/*     the number of the last-read line in each file
+ *     is kept in cline[0-2]
+*/
+int cline[3];
+/*     the latest known correspondence between line
+ *     numbers of the 3 files is stored in last[1-3]
+*/
+int last[4];
+int eflag;
+int debug = 0;
+
+void repos(int nchar)
+{
+       register i;
+       for (i = 0; i < 2; i++)
+               fseek(fp[i], (long) -nchar, 1);
+}
+
+void trouble(void)
+{
+       fprintf(stderr, "diff3: logic error\n");
+       abort();
+}
+
+int digit(char c)
+{
+       return (c >= '0' && c <= '9');
+}
+
+
+int number(char **lc)
+{
+       register int nn;
+       nn = 0;
+       while (digit(**lc))
+               nn = nn * 10 + *(*lc)++ - '0';
+       return (nn);
+}
+
+int getline(FILE * b)
+{
+       register i, c;
+       for (i = 0; i < sizeof(line) - 1; i++) {
+               c = getc(b);
+               if (c == EOF)
+                       break;
+               line[i] = c;
+               if (c == '\n') {
+                       line[++i] = 0;
+                       return (i);
+               }
+       }
+       return (0);
+}
+
+int getchange(FILE * b)
+{
+       while (getline(b))
+               if (digit(line[0]))
+                       return (1);
+       return (0);
+}
+
+/*pick up the line numbers of allcahnges from
+ * one change file
+ * (this puts the numbers in a vector, which is not
+ * strictly necessary, since the vector is processed
+ * in one sequential pass. The vector could be optimized
+ * out of existence)
+*/
+
+int readin(const char *name, struct diff *dd)
+{
+       register int i;
+       int a, b, c, d;
+       char kind;
+       char *p;
+       fp[0] = fopen(name, "r");
+       for (i = 0; getchange(fp[0]); i++) {
+               if (i >= NC) {
+                       fprintf(stderr, "diff3: too many changes\n");
+                       exit(0);
+               }
+               p = line;
+               a = b = number(&p);
+               if (*p == ',') {
+                       p++;
+                       b = number(&p);
+               }
+               kind = *p++;
+               c = d = number(&p);
+               if (*p == ',') {
+                       p++;
+                       d = number(&p);
+               }
+               if (kind == 'a')
+                       a++;
+               if (kind == 'd')
+                       c++;
+               b++;
+               d++;
+               dd[i].old.from = a;
+               dd[i].old.to = b;
+               dd[i].new.from = c;
+               dd[i].new.to = d;
+       }
+       dd[i].old.from = dd[i - 1].old.to;
+       dd[i].new.from = dd[i - 1].new.to;
+       fclose(fp[0]);
+       return (i);
+}
+
+
+void separate(char *s)
+{
+       printf("====%s\n", s);
+}
+
+/*     print the range of line numbers, rold.from  thru rold.to
+ *     as n1,n2 or n1
+*/
+
+void prange(struct range *rold)
+{
+       if (rold->to <= rold->from)
+               printf("%da\n", rold->from - 1);
+       else {
+               printf("%d", rold->from);
+               if (rold->to > rold->from + 1)
+                       printf(",%d", rold->to - 1);
+               printf("c\n");
+       }
+}
+
+/*     skip to just befor line number from in file i
+ *     if "pr" is nonzero, print all skipped stuff
+ *     with string pr as a prefix
+*/
+
+int skip(int i, int from, char *pr)
+{
+       register int j, n;
+       for (n = 0; cline[i] < from - 1; n += j) {
+               if ((j = getline(fp[i])) == 0)
+                       trouble();
+               if (pr)
+                       printf("%s%s", pr, line);
+               cline[i]++;
+       }
+       return (n);
+}
+
+/*     the range of ines rold.from thru rold.to in file i
+ *     is to be changed. it is to be printed only if
+ *     it does not duplicate something to be printed later
+*/
+void change(int i, struct range *rold, int dup)
+{
+       printf("%d:", i);
+       last[i] = rold->to;
+       prange(rold);
+       if (dup)
+               return;
+       if (debug)
+               return;
+       i--;
+       skip(i, rold->from, (char *) 0);
+       skip(i, rold->to, "  ");
+}
+
+
+/*     no difference was reported by diff between file 1(or 2)
+ *     and file 3, and an artificial dummy difference (trange)
+ *     must be ginned up to correspond to the change reported
+ *     in the other file
+*/
+void keep(int i, struct range *rold, struct range *rnew)
+{
+       register int delta;
+       struct range trange;
+       delta = last[3] - last[i];
+       trange.from = rnew->from - delta;
+       trange.to = rnew->to - delta;
+       change(i, &trange, 1);
+}
+
+
+/*     return 1 or 0 according as the old range
+ *     (in file 1) contains exactly the same data
+ *     as the new range (in file 2)
+*/
+
+int duplicate(struct range *r1, struct range *r2)
+{
+       register int c, d;
+       register int nchar;
+       int nline;
+       if (r1->to - r1->from != r2->to - r2->from)
+               return (0);
+       skip(0, r1->from, (char *) 0);
+       skip(1, r2->from, (char *) 0);
+       nchar = 0;
+       for (nline = 0; nline < r1->to - r1->from; nline++) {
+               do {
+                       c = getc(fp[0]);
+                       d = getc(fp[1]);
+                       if (c == -1 || d == -1)
+                               trouble();
+                       nchar++;
+                       if (c != d) {
+                               repos(nchar);
+                               return 0;
+                       }
+               } while (c != '\n');
+       }
+       repos(nchar);
+       return (1);
+}
+
+/*     collect an editing script for later regurgitation
+*/
+int edit(struct diff *diff, int dup, int j)
+{
+       if (((dup + 1) & eflag) == 0)
+               return (j);
+       j++;
+       de[j].old.from = diff->old.from;
+       de[j].old.to = diff->old.to;
+       de[j].new.from = de[j - 1].new.to
+           + skip(2, diff->new.from, (char *) 0);
+       de[j].new.to = de[j].new.from + skip(2, diff->new.to, (char *) 0);
+       return (j);
+}
+
+/*             regurgitate */
+void edscript(int n)
+{
+       register j, k;
+       char block[512];
+       for (n = n; n > 0; n--) {
+               prange(&de[n].old);
+               fseek(fp[2], (long) de[n].new.from, 0);
+               for (k = de[n].new.to - de[n].new.from; k > 0; k -= j) {
+                       j = k > 512 ? 512 : k;
+                       if (fread(block, 1, j, fp[2]) != j)
+                               trouble();
+                       fwrite(block, 1, j, stdout);
+               }
+               printf(".\n");
+       }
+}
+
+
+void merge(int m1, int m2)
+{
+       register struct diff *d1, *d2, *d3;
+       int dup;
+       int j;
+       int t1, t2;
+       d1 = d13;
+       d2 = d23;
+       j = 0;
+       for (; (t1 = d1 < d13 + m1) | (t2 = d2 < d23 + m2);) {
+               if (debug) {
+                       printf("%d,%d=%d,%d %d,%d=%d,%d\n",
+                              d1->old.from, d1->old.to,
+                              d1->new.from, d1->new.to,
+                              d2->old.from, d2->old.to,
+                              d2->new.from, d2->new.to);
+               }
+/*                     first file is different from others*/
+               if (!t2 || t1 && d1->new.to < d2->new.from) {
+/*                     stuff peculiar to 1st file */
+                       if (eflag == 0) {
+                               separate("1");
+                               change(1, &d1->old, 0);
+                               keep(2, &d1->old, &d1->new);
+                               change(3, &d1->new, 0);
+                       }
+                       d1++;
+                       continue;
+               }
+/*                     second file is different from others*/
+               if (!t1 || t2 && d2->new.to < d1->new.from) {
+                       if (eflag == 0) {
+                               separate("2");
+                               keep(1, &d2->old, &d2->new);
+                               change(2, &d2->old, 0);
+                               change(3, &d2->new, 0);
+                       }
+                       d2++;
+                       continue;
+               }
+/*                     merge overlapping changes in first file
+ *                     this happens after extension see below*/
+               if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) {
+                       d1[1].old.from = d1->old.from;
+                       d1[1].new.from = d1->new.from;
+                       d1++;
+                       continue;
+               }
+/*                     merge overlapping changes in second*/
+               if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) {
+                       d2[1].old.from = d2->old.from;
+                       d2[1].new.from = d2->new.from;
+                       d2++;
+                       continue;
+               }
+/*                     stuff peculiar to third file or different in all*/
+               if (d1->new.from == d2->new.from &&
+                   d1->new.to == d2->new.to) {
+                       dup = duplicate(&d1->old, &d2->old);
+/*                             dup=0 means all files differ
+ *                             dup =1 meands files 1&2 identical*/
+                       if (eflag == 0) {
+                               separate(dup ? "3" : "");
+                               change(1, &d1->old, dup);
+                               change(2, &d2->old, 0);
+                               d3 = d1->old.to > d1->old.from ? d1 : d2;
+                               change(3, &d3->new, 0);
+                       } else
+                               j = edit(d1, dup, j);
+                       d1++;
+                       d2++;
+                       continue;
+               }
+/*                     overlapping changes from file1 & 2
+ *                     extend changes appropriately to
+ *                     make them coincide*/
+               if (d1->new.from < d2->new.from) {
+                       d2->old.from -= d2->new.from - d1->new.from;
+                       d2->new.from = d1->new.from;
+               } else if (d2->new.from < d1->new.from) {
+                       d1->old.from -= d1->new.from - d2->new.from;
+                       d1->new.from = d2->new.from;
+               }
+               if (d1->new.to > d2->new.to) {
+                       d2->old.to += d1->new.to - d2->new.to;
+                       d2->new.to = d1->new.to;
+               } else if (d2->new.to > d1->new.to) {
+                       d1->old.to += d2->new.to - d1->new.to;
+                       d1->new.to = d2->new.to;
+               }
+       }
+       if (eflag)
+               edscript(j);
+}
+
+int main(int argc, char *argv[])
+{
+       register int i, m, n;
+       if (*argv[1] == '-') {
+               switch (argv[1][1]) {
+               default:
+                       eflag = 3;
+                       break;
+               case '3':
+                       eflag = 2;
+                       break;
+               case 'x':
+                       eflag = 1;
+               }
+               argv++;
+               argc--;
+       }
+       if (argc < 6) {
+               fprintf(stderr, "diff3: arg count\n");
+               exit(1);
+       }
+       m = readin(argv[1], d13);
+       n = readin(argv[2], d23);
+       for (i = 0; i <= 2; i++)
+               if ((fp[i] = fopen(argv[i + 3], "r")) == NULL) {
+                       printf("diff3: can't open %s\n", argv[i + 3]);
+                       exit(1);
+               }
+       merge(m, n);
+}
diff --git a/Applications/V7/cmd/diffh.c b/Applications/V7/cmd/diffh.c
new file mode 100644 (file)
index 0000000..68a375a
--- /dev/null
@@ -0,0 +1,265 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define C 3
+#define RANGE 30
+#define LEN 255
+#define INF 16384
+
+char *text[2][RANGE];
+long lineno[2] = { 1, 1 };     /*no. of 1st stored line in each file */
+
+int ntext[2];                  /*number of stored lines in each */
+long n0, n1;                   /*scan pointer in each */
+int bflag;
+int debug = 0;
+FILE *file[2];
+
+void error(const char *s, const char *t)
+{
+       fprintf(stderr, "diffh: %s%s\n", s, t);
+       exit(1);
+}
+
+void progerr(const char *s)
+{
+       error("program error ", s);
+}
+
+
+void movstr(const char *s, char *t)
+{
+       while (*t++ = *s++)
+               continue;
+}
+
+
+int range(long a, int b)
+{
+       if (b == INF)
+               printf("%ld,$", a);
+       else if (b == 0)
+               printf("%ld", a);
+       else
+               printf("%ld,%ld", a, a + b);
+}
+
+
+int change(long a, int b, long c, int d, char *s)
+{
+       range(a, b);
+       printf("%s", s);
+       range(c, d);
+       printf("\n");
+}
+
+/*stub for resychronization beyond limits of text buf*/
+int hardsynch(void)
+{
+       change(n0, INF, n1, INF, "c");
+       printf("---change record omitted\n");
+       error("can't resynchronize", "");
+       return (0);
+}
+
+       /* return pointer to line n of file f */
+char *getl(int f, long n)
+{
+       char *t;
+       int delta, nt;
+      again:
+       delta = n - lineno[f];
+       nt = ntext[f];
+       if (delta < 0)
+               progerr("1");
+       if (delta < nt)
+               return (text[f][delta]);
+       if (delta > nt)
+               progerr("2");
+       if (nt >= RANGE)
+               progerr("3");
+       if (feof(file[f]))
+               return (NULL);
+       t = text[f][nt];
+       if (t == 0) {
+               t = text[f][nt] = malloc(LEN + 1);
+               if (t == NULL)
+                       if (hardsynch())
+                               goto again;
+                       else
+                               progerr("5");
+       }
+       t = fgets(t, LEN, file[f]);
+       if (t != NULL)
+               ntext[f]++;
+       return (t);
+}
+
+       /*remove thru line n of file f from storage */
+void clrl(int f, long n)
+{
+       register int i, j;
+       j = n - lineno[f] + 1;
+       for (i = 0; i + j < ntext[f]; i++)
+               movstr(text[f][i + j], text[f][i]);
+       lineno[f] = n + 1;
+       ntext[f] -= j;
+}
+
+
+int output(int a, int b)
+{
+       register int i;
+       char *s;
+       if (a < 0)
+               change(n0 - 1, 0, n1, b, "a");
+       else if (b < 0)
+               change(n0, a, n1 - 1, 0, "d");
+       else
+               change(n0, a, n1, b, "c");
+       for (i = 0; i <= a; i++) {
+               s = getl(0, n0 + i);
+               if (s == NULL)
+                       break;
+               printf("< %s", s);
+               clrl(0, n0 + i);
+       }
+       n0 += i - 1;
+       if (a >= 0 && b >= 0)
+               printf("---\n");
+       for (i = 0; i <= b; i++) {
+               s = getl(1, n1 + i);
+               if (s == NULL)
+                       break;
+               printf("> %s", s);
+               clrl(1, n1 + i);
+       }
+       n1 += i - 1;
+       return (1);
+}
+
+int cmp(const char *s, const char *t)
+{
+       if (debug)
+               printf("%s:%s\n", s, t);
+       for (;;) {
+               if (bflag && isspace(*s) && isspace(*t)) {
+                       while (isspace(*++s));
+                       while (isspace(*++t));
+               }
+               if (*s != *t || *s == 0)
+                       break;
+               s++;
+               t++;
+       }
+       return (*s - *t);
+}
+
+/* synch on C successive matches*/
+int easysynch(void)
+{
+       int i, j;
+       register k, m;
+       char *s0, *s1;
+       for (i = j = 1; i < RANGE && j < RANGE; i++, j++) {
+               s0 = getl(0, n0 + i);
+               if (s0 == NULL)
+                       return (output(INF, INF));
+               for (k = C - 1; k < j; k++) {
+                       for (m = 0; m < C; m++)
+                               if (cmp(getl(0, n0 + i - m),
+                                       getl(1, n1 + k - m)) != 0)
+                                       goto cont1;
+                       return (output(i - C, k - C));
+                     cont1:;
+               }
+               s1 = getl(1, n1 + j);
+               if (s1 == NULL)
+                       return (output(INF, INF));
+               for (k = C - 1; k <= i; k++) {
+                       for (m = 0; m < C; m++)
+                               if (cmp(getl(0, n0 + k - m),
+                                       getl(1, n1 + j - m)) != 0)
+                                       goto cont2;
+                       return (output(k - C, j - C));
+                     cont2:;
+               }
+       }
+       return (0);
+}
+
+FILE *dopen(const char *f1, const char *f2)
+{
+       FILE *f;
+       char b[100], *bptr;
+       const char *eptr;
+       struct stat statbuf;
+       if (cmp(f1, "-") == 0)
+               if (cmp(f2, "-") == 0)
+                       error("can't do - -", "");
+               else
+                       return (stdin);
+       if (stat(f1, &statbuf) == -1)
+               error("can't access ", f1);
+
+       /* FIXME: buffer length is not sanely checked, should
+          strdup and then modify the copy in situ */
+       if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
+               for (bptr = b; *bptr = *f1++; bptr++);
+               *bptr++ = '/';
+               for (eptr = f2; *eptr; eptr++)
+                       if (*eptr == '/' && eptr[1] != 0 && eptr[1] != '/')
+                               f2 = eptr + 1;
+               while (*bptr++ = *f2++);
+               f1 = b;
+       }
+       f = fopen(f1, "r");
+       if (f == NULL)
+               error("can't open", f1);
+       return (f);
+}
+
+
+
+int main(int argc, const char *argv[])
+{
+       char *s0, *s1;
+       if (*argv[1] == '-') {
+               argc--;
+               argv++;
+               while (*++argv[0])
+                       if (*argv[0] == 'b')
+                               bflag++;
+       }
+       if (argc != 3)
+               error("must have 2 file arguments", "");
+       file[0] = dopen(argv[1], argv[2]);
+       file[1] = dopen(argv[2], argv[1]);
+       for (;;) {
+               s0 = getl(0, ++n0);
+               s1 = getl(1, ++n1);
+               if (s0 == NULL || s1 == NULL)
+                       break;
+               if (cmp(s0, s1) != 0) {
+                       if (!easysynch() && !hardsynch())
+                               progerr("5");
+               } else {
+                       clrl(0, n0);
+                       clrl(1, n1);
+               }
+       }
+       if (s0 == NULL && s1 == NULL)
+               return 0;
+       if (s0 == NULL)
+               output(-1, INF);
+       if (s1 == NULL)
+               output(INF, -1);
+       return 0;
+}
diff --git a/Applications/V7/cmd/join.c b/Applications/V7/cmd/join.c
new file mode 100644 (file)
index 0000000..d89bfef
--- /dev/null
@@ -0,0 +1,209 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+/*     join F1 F2 on stuff */
+
+#include       <stdio.h>
+#include       <stdlib.h>
+#include       <string.h>
+#include       <unistd.h>
+#include       <err.h>
+
+#define F1 0
+#define F2 1
+#define        NFLD    20      /* max field per line */
+#define comp() cmp(ppi[F1][j1],ppi[F2][j2])
+
+FILE *f[2];
+char buf[2][BUFSIZ];   /*input lines */
+char *ppi[2][NFLD];    /* pointers to fields in lines */
+char *s1,*s2;
+int    j1      = 1;    /* join of this field of file 1 */
+int    j2      = 1;    /* join of this field of file 2 */
+int    olist[2*NFLD];  /* output these fields */
+int    olistf[2*NFLD]; /* from these files */
+int    no;     /* number of entries in olist */
+int    sep1    = ' ';  /* default field separator */
+int    sep2    = '\t';
+const char *null       = "";
+int    unpub1;
+int    unpub2;
+int    aflg;
+
+int cmp(const char *s1, const char *s2)
+{
+       return(strcmp(s1, s2));
+}
+
+int input(int n)               /* get input line and split into fields */
+{
+       register int i, c;
+       char *bp;
+       char **pp;
+
+       bp = buf[n];
+       pp = ppi[n];
+       if (fgets(bp, BUFSIZ, f[n]) == NULL)
+               return(0);
+       for (i = 0; ; i++) {
+               if (sep1 == ' ')        /* strip multiples */
+                       while ((c = *bp) == sep1 || c == sep2)
+                               bp++;   /* skip blanks */
+               else
+                       c = *bp;
+               if (c == '\n' || c == '\0')
+                       break;
+               *pp++ = bp;     /* record beginning */
+               while ((c = *bp) != sep1 && c != '\n' && c != sep2 && c != '\0')
+                       bp++;
+               *bp++ = '\0';   /* mark end by overwriting blank */
+                       /* fails badly if string doesn't have \n at end */
+       }
+       *pp = 0;
+       return(i);
+}
+
+int output(int on1, int on2)   /* print items from olist */
+{
+       int i;
+       const char *temp;
+
+       if (no <= 0) {  /* default case */
+               printf("%s", on1? ppi[F1][j1]: ppi[F2][j2]);
+               for (i = 0; i < on1; i++)
+                       if (i != j1)
+                               printf("%c%s", sep1, ppi[F1][i]);
+               for (i = 0; i < on2; i++)
+                       if (i != j2)
+                               printf("%c%s", sep1, ppi[F2][i]);
+               printf("\n");
+       } else {
+               for (i = 0; i < no; i++) {
+                       temp = ppi[olistf[i]][olist[i]];
+                       if(olistf[i]==F1 && on1<=olist[i] ||
+                          olistf[i]==F2 && on2<=olist[i] ||
+                          *temp==0)
+                               temp = null;
+                       printf("%s", temp);
+                       if (i == no - 1)
+                               printf("\n");
+                       else
+                               printf("%c", sep1);
+               }
+       }
+}
+
+int main(int argc, const char *argv[])
+{
+       int i;
+       int n1, n2;
+       long top2, bot2;
+
+       while (argc > 1 && argv[1][0] == '-') {
+               if (argv[1][1] == '\0')
+                       break;
+               switch (argv[1][1]) {
+               case 'a':
+                       switch(argv[1][2]) {
+                       case '1':
+                               aflg |= 1;
+                               break;
+                       case '2':
+                               aflg |= 2;
+                               break;
+                       default:
+                               aflg |= 3;
+                       }
+                       break;
+               case 'e':
+                       null = argv[2];
+                       argv++;
+                       argc--;
+                       break;
+               case 't':
+                       sep1 = sep2 = argv[1][2];
+                       break;
+               case 'o':
+                       for (no = 0; no < 2*NFLD; no++) {
+                               if (argv[2][0] == '1' && argv[2][1] == '.') {
+                                       olistf[no] = F1;
+                                       olist[no] = atoi(&argv[2][2]);
+                               } else if (argv[2][0] == '2' && argv[2][1] == '.') {
+                                       olist[no] = atoi(&argv[2][2]);
+                                       olistf[no] = F2;
+                               } else
+                                       break;
+                               argc--;
+                               argv++;
+                       }
+                       break;
+               case 'j':
+                       if (argv[1][2] == '1')
+                               j1 = atoi(argv[2]);
+                       else if (argv[1][2] == '2')
+                               j2 = atoi(argv[2]);
+                       else
+                               j1 = j2 = atoi(argv[2]);
+                       argc--;
+                       argv++;
+                       break;
+               }
+               argc--;
+               argv++;
+       }
+       for (i = 0; i < no; i++)
+               olist[i]--;     /* 0 origin */
+       if (argc != 3)
+               errx(1, "usage: join [-j1 x -j2 y] [-o list] file1 file2");
+       j1--;
+       j2--;   /* everyone else believes in 0 origin */
+       s1 = ppi[F1][j1];
+       s2 = ppi[F2][j2];
+       if (argv[1][0] == '-')
+               f[F1] = stdin;
+       else if ((f[F1] = fopen(argv[1], "r")) == NULL)
+               errx(1, "can't open %s", argv[1]);
+       if ((f[F2] = fopen(argv[2], "r")) == NULL)
+               errx(1, "can't open %s", argv[2]);
+
+#define get1() n1=input(F1)
+#define get2() n2=input(F2)
+       get1();
+       bot2 = ftell(f[F2]);
+       get2();
+       while(n1>0 && n2>0 || aflg!=0 && n1+n2>0) {
+               if(n1>0 && n2>0 && comp()>0 || n1==0) {
+                       if(aflg&2) output(0, n2);
+                       bot2 = ftell(f[F2]);
+                       get2();
+               } else if(n1>0 && n2>0 && comp()<0 || n2==0) {
+                       if(aflg&1) output(n1, 0);
+                       get1();
+               } else /*(n1>0 && n2>0 && comp()==0)*/ {
+                       while(n2>0 && comp()==0) {
+                               output(n1, n2);
+                               top2 = ftell(f[F2]);
+                               get2();
+                       }
+                       fseek(f[F2], bot2, 0);
+                       get2();
+                       get1();
+                       for(;;) {
+                               if(n1>0 && n2>0 && comp()==0) {
+                                       output(n1, n2);
+                                       get2();
+                               } else if(n1>0 && n2>0 && comp()<0 || n2==0) {
+                                       fseek(f[F2], bot2, 0);
+                                       get2();
+                                       get1();
+                               } else /*(n1>0 && n2>0 && comp()>0 || n1==0)*/{
+                                       fseek(f[F2], top2, 0);
+                                       bot2 = top2;
+                                       get2();
+                                       break;
+                               }
+                       }
+               }
+       }
+       return(0);
+}
diff --git a/Applications/V7/cmd/look.c b/Applications/V7/cmd/look.c
new file mode 100644 (file)
index 0000000..9053188
--- /dev/null
@@ -0,0 +1,164 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+FILE *dfile;
+const char *filenam  = "/usr/dict/words";
+
+int fold;
+int dict;
+int tab;
+char entry[250];
+char word[250];
+char key[50];
+
+
+int compare(char *s, char *t)
+{
+       for(;*s==*t;s++,t++)
+               if(*s==0)
+                       return(0);
+       return(*s==0? -1:
+               *t==0? 1:
+               *s<*t? -2:
+               2);
+}
+
+int getword(char *w)
+{
+       register int c;
+       for(;;) {
+               c = getc(dfile);
+               if(c==EOF)
+                       return(0);
+               if(c=='\n')
+                       break;
+               *w++ = c;
+       }
+       *w = 0;
+       return(1);
+}
+
+int canon(const char *old, char *new)
+{
+       register int c;
+       for(;;) {
+               *new = c = *old++;
+               if(c==0||c==tab) {
+                       *new = 0;
+                       break;
+               }
+               if(dict) {
+                       if(!isalnum(c))
+                               continue;
+               }
+               if(fold) {
+                       if(isupper(c))
+                               *new += 'a' - 'A';
+               }
+               new++;
+       }
+}
+
+int main(int argc, const char *argv[])
+{
+       register int c;
+       long top,bot,mid;
+       while(argc>=2 && *argv[1]=='-') {
+               for(;;) {
+                       switch(*++argv[1]) {
+                       case 'd':
+                               dict++;
+                               continue;
+                       case 'f':
+                               fold++;
+                               continue;
+                       case 't':
+                               tab = argv[1][1];
+                               if(tab)
+                                       ++argv[1];
+                               continue;
+                       case 0:
+                               break;
+                       default:
+                               continue;
+                       }
+                       break;
+               }
+               argc --;
+               argv++;
+       }
+       if(argc<=1)
+               return 0;
+       if(argc==2) {
+               fold++;
+               dict++;
+       } else
+               filenam = argv[2];
+       dfile = fopen(filenam,"r");
+       if(dfile==NULL) {
+               fprintf(stderr,"look: can't open %s\n",filenam);
+               exit(2);
+       }
+       canon(argv[1],key);
+       bot = 0;
+       fseek(dfile,0L,2);
+       top = ftell(dfile);
+       for(;;) {
+               mid = (top+bot)/2;
+               fseek(dfile,mid,0);
+               do {
+                       c = getc(dfile);
+                       mid++;
+               } while(c!=EOF && c!='\n');
+               if(!getword(entry))
+                       break;
+               canon(entry,word);
+               switch(compare(key,word)) {
+               case -2:
+               case -1:
+               case 0:
+                       if(top<=mid)
+                               break;
+                       top = mid;
+                       continue;
+               case 1:
+               case 2:
+                       bot = mid;
+                       continue;
+               }
+               break;
+       }
+       fseek(dfile,bot,0);
+       while(ftell(dfile)<top) {
+               if(!getword(entry))
+                       return 0;
+               canon(entry,word);
+               switch(compare(key,word)) {
+               case -2:
+                       return 0;
+               case -1:
+               case 0:
+                       puts(entry);
+                       break;
+               case 1:
+               case 2:
+                       continue;
+               }
+               break;
+       }
+       while(getword(entry)) {
+               canon(entry,word);
+               switch(compare(key,word)) {
+               case -1:
+               case 0:
+                       puts(entry);
+                       continue;
+               }
+               break;
+       }
+       return 0;
+}
diff --git a/Applications/V7/cmd/makekey.c b/Applications/V7/cmd/makekey.c
new file mode 100644 (file)
index 0000000..e399ef7
--- /dev/null
@@ -0,0 +1,23 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+/*
+ * You send it 10 bytes.
+ * It sends you 13 bytes.
+ * The transformation is expensive to perform
+ * (a significant part of a second).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int argc, const char *argv[])
+{
+       char key[8];
+       char salt[2];
+       
+       read(0, key, 8);
+       read(0, salt, 2);
+       write(1, crypt(key, salt), 13);
+       return(0);
+}
diff --git a/Applications/V7/cmd/mesg.c b/Applications/V7/cmd/mesg.c
new file mode 100644 (file)
index 0000000..be6d110
--- /dev/null
@@ -0,0 +1,52 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+/*
+ * mesg -- set current tty to accept or
+ *     forbid write permission.
+ *
+ *     mesg [y] [n]
+ *             y allow messages
+ *             n forbid messages
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+struct stat sbuf;
+
+char *tty;
+
+void newmode(int m)
+{
+       if(chmod(tty,m)<0)
+               err(1, "cannot change mode");
+}
+
+int main(int argc, char *argv[])
+{
+       int r=0;
+       tty = ttyname(2);
+       if(stat(tty, &sbuf) < 0) err(1, "cannot stat");
+       if(argc < 2) {
+               if(sbuf.st_mode & 02)
+                       fprintf(stderr,"is y\n");
+               else {  r=1;
+                       fprintf(stderr,"is n\n");
+               }
+       } else  switch(*argv[1]) {
+               case 'y':
+                       newmode(0622); break;
+
+               case 'n':
+                       newmode(0600); r=1; break;
+
+               default:
+                       errx(-1, "usage: mesg [y] [n]");
+               }
+       exit(r);
+}
+
diff --git a/Applications/V7/cmd/newgrp.c b/Applications/V7/cmd/newgrp.c
new file mode 100644 (file)
index 0000000..39cbd8c
--- /dev/null
@@ -0,0 +1,66 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied and taught about using the passwd file listed shell for FUZIX */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <grp.h>
+#include <pwd.h>
+
+struct group   *grp;
+struct passwd  *pwd;
+
+void done(const char *shell)
+{
+       register int i;
+       const char *sp = strrchr(shell, '/');
+       
+       if (sp)
+               sp++;
+       else
+               sp = shell;
+
+       setuid(getuid());
+       for (i=3; i<15; i++)
+               close(i);
+       execl(shell, sp, 0);
+       printf("No shell!\n");
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       register int i;
+
+       if((pwd=getpwuid(getuid())) == NULL) {
+               printf("You do not exist!\n");
+               done("/bin/sh");
+       }
+
+       if(argc != 2) {
+               printf("usage: newgrp groupname\n");
+               done(pwd->pw_shell);
+       }
+       if((grp=getgrnam(argv[1])) == NULL) {
+               printf("%s: no such group\n", argv[1]);
+               done(pwd->pw_shell);
+       }
+       for(i=0;grp->gr_mem[i];i++) 
+               if(strcmp(grp->gr_mem[i], pwd->pw_name) == 0)
+                       break;
+       if(grp->gr_mem[i] == 0 && strcmp(grp->gr_name,"other")) {
+               printf("Sorry\n");
+               done(pwd->pw_shell);
+       }
+
+       if(grp->gr_passwd[0] != '\0' && pwd->pw_passwd[0] == '\0') {
+               if(strcmp(grp->gr_passwd, crypt(getpass("Password:"),grp->gr_passwd)) != 0) {
+                       printf("Sorry\n");
+                       done(pwd->pw_shell);
+               }
+       }
+       if(setgid(grp->gr_gid) < 0)
+               perror("setgid");
+       done(pwd->pw_shell);
+}
diff --git a/Applications/V7/cmd/pr.c b/Applications/V7/cmd/pr.c
new file mode 100644 (file)
index 0000000..6d500e8
--- /dev/null
@@ -0,0 +1,425 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+/*
+ *   print file with headings
+ *  2+head+2+page[56]+5
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+
+int    ncol    = 1;
+const char     *header;
+int    col;
+int    icol;
+FILE   *file;
+char   *bufp;
+#define        BUFS    6720
+char   buffer[BUFS];   /* for multi-column output */
+char   obuf[BUFSIZ];
+#define        FF      014
+int    line;
+char   *colp[72];
+int    nofile;
+char   isclosed[10];
+FILE   *ifile[10];
+char   **lastarg;
+int    peekc;
+int    fpage;
+int    page;
+int    colw;
+int    nspace;
+int    width   = 72;
+int    length  = 66;
+int    plength = 61;
+int    margin  = 10;
+int    ntflg;
+int    mflg;
+int    tabc;
+char   *tty;
+int    mode;
+
+
+void done(void)
+{
+
+       if (tty)
+               chmod(tty, mode);
+       exit(0);
+}
+
+void onintr(int sig)
+{
+
+       if (tty)
+               chmod(tty, mode);
+       _exit(1);
+}
+
+void fixtty(void)
+{
+       struct stat sbuf;
+
+       tty = ttyname(1);
+       if (tty == 0)
+               return;
+       stat(tty, &sbuf);
+       mode = sbuf.st_mode&0777;
+       chmod(tty, 0600);
+}
+
+
+
+void nexbuf(void)
+{
+       register int n;
+       register char *rbufp;
+
+       rbufp = bufp;
+       n = &buffer[BUFS] - rbufp;
+       if (n>512)
+               n = 512;
+       if(feof(file) ||
+          (n=fread(rbufp,1,n,file)) <= 0){
+               fclose(file);
+               *rbufp = 0376;
+       }
+       else {
+               rbufp += n;
+               if (rbufp >= &buffer[BUFS])
+                       rbufp = buffer;
+               *rbufp = 0375;
+       }
+       bufp = rbufp;
+}
+
+int tpgetc(int ai)
+{
+       register char **p;
+       register int c, i;
+
+       i = ai;
+       if (mflg) {
+               if((c=getc(ifile[i])) == EOF) {
+                       if (isclosed[i]==0) {
+                               isclosed[i] = 1;
+                               if (--nofile <= 0)
+                                       return(0);
+                       }
+                       return('\n');
+               }
+               if (c==FF && ncol>0)
+                       c = '\n';
+               return(c);
+       }
+loop:
+       c = **(p = &colp[i]) & 0377;
+       if (c == 0375) {
+               nexbuf();
+               c = **p & 0377;
+       }
+       if (c == 0376)
+               return(0);
+       (*p)++;
+       if (*p >= &buffer[BUFS])
+               *p = buffer;
+       if (c==0)
+               goto loop;
+       return(c);
+}
+
+pgetc(int i)
+{
+       register int c;
+
+       if (peekc) {
+               c = peekc;
+               peekc = 0;
+       } else
+               c = tpgetc(i);
+       if (tabc)
+               return(c);
+       switch (c) {
+
+       case '\t':
+               icol++;
+               if ((icol&07) != 0)
+                       peekc = '\t';
+               return(' ');
+
+       case '\n':
+               icol = 0;
+               break;
+
+       case 010:
+       case 033:
+               icol--;
+               break;
+       }
+       if (c >= ' ')
+               icol++;
+       return(c);
+}
+
+void putcp(int c)
+{
+       if (page >= fpage)
+               putchar(c);
+}
+
+
+void put(int ac)
+{
+       register int ns, c;
+
+       c = ac;
+       if (tabc) {
+               putcp(c);
+               if (c=='\n')
+                       line++;
+               return;
+       }
+       switch (c) {
+
+       case ' ':
+               nspace++;
+               col++;
+               return;
+
+       case '\n':
+               col = 0;
+               nspace = 0;
+               line++;
+               break;
+
+       case 010:
+       case 033:
+               if (--col<0)
+                       col = 0;
+               if (--nspace<0)
+                       nspace = 0;
+
+       }
+       while(nspace) {
+               if (nspace>2 && col > (ns=((col-nspace)|07))) {
+                       nspace = col-ns-1;
+                       putcp('\t');
+               } else {
+                       nspace--;
+                       putcp(' ');
+               }
+       }
+       if (c >= ' ')
+               col++;
+       putcp(c);
+}
+
+void putpage(void)
+{
+       register int lastcol, i, c;
+       int j;
+
+       if (ncol==0) {
+               while (line<plength) {
+                       while((c = tpgetc(0)) && c!='\n' && c!=FF)
+                               putcp(c);
+                       putcp('\n');
+                       line++;
+                       if (c==FF)
+                               break;
+               }
+               return;
+       }
+       colp[0] = colp[ncol];
+       if (mflg==0) for (i=1; i<=ncol; i++) {
+               colp[i] = colp[i-1];
+               for (j = margin; j<length; j++)
+                       while((c=tpgetc(i))!='\n')
+                               if (c==0)
+                                       break;
+       }
+       while (line<plength) {
+               lastcol = colw;
+               for (i=0; i<ncol; i++) {
+                       while ((c=pgetc(i)) && c!='\n')
+                               if (col<lastcol || tabc!=0)
+                                       put(c);
+                       if (c==0)
+                               continue;
+                       if (tabc)
+                               put(tabc);
+                       else while (col<lastcol)
+                               put(' ');
+                       lastcol += colw;
+               }
+               while ((c = pgetc(ncol)) && c!='\n')
+                       put(c);
+               put('\n');
+       }
+}
+
+void mopen(char **ap)
+{
+       register char **p, *p1;
+
+       p = ap;
+       while((p1 = *p) && p++ <= lastarg) {
+               if((ifile[nofile]=fopen(p1, "r")) == NULL){
+                       isclosed[nofile] = 1;
+                       nofile--;
+               }
+               else
+                       isclosed[nofile] = 0;
+               if(++nofile>=10) {
+                       fprintf(stderr, "pr: Too many args\n");
+                       done();
+               }
+       }
+}
+
+void print(char *fp, char **argp)
+{
+       struct stat sbuf;
+       register sncol;
+       register const char *sheader;
+       register char *cbuf;
+       char linebuf[150], *cp;
+
+       if (ntflg)
+               margin = 0;
+       else
+               margin = 10;
+       if (length <= margin)
+               length = 66;
+       if (width <= 0)
+               width = 72;
+       if (ncol>72 || ncol>width) {
+               fprintf(stderr, "pr: No room for columns.\n");
+               done();
+       }
+       if (mflg) {
+               mopen(argp);
+               ncol = nofile;
+       }
+       colw = width/ncol;
+       sncol = ncol;
+       sheader = header;
+       plength = length-5;
+       if (ntflg)
+               plength = length;
+       if (--ncol<0)
+               ncol = 0;
+       if (mflg)
+               fp = 0;
+       if (fp) {
+               if((file=fopen(fp, "r"))==NULL) {
+                       if (tty==NULL)
+                               fprintf(stderr, "pr: can't open %s\n", fp);
+                       ncol = sncol;
+                       header = sheader;
+                       return;
+               }
+               stat(fp, &sbuf);
+       } else {
+               file = stdin;
+               time(&sbuf.st_mtime);
+       }
+       if (header == 0)
+               header = fp?fp:"";
+       cbuf = ctime(&sbuf.st_mtime);
+       cbuf[16] = '\0';
+       cbuf[24] = '\0';
+       page = 1;
+       icol = 0;
+       colp[ncol] = bufp = buffer;
+       if (mflg==0)
+               nexbuf();
+       while (mflg&&nofile || (!mflg)&&tpgetc(ncol)>0) {
+               if (mflg==0) {
+                       colp[ncol]--;
+                       if (colp[ncol] < buffer)
+                               colp[ncol] = &buffer[BUFS];
+               }
+               line = 0;
+               if (ntflg==0) {
+                       snprintf(linebuf, 150, "\n\n%s %s  %s Page %d\n\n\n",
+                               cbuf+4, cbuf+20, header, page);
+                       for(cp=linebuf;*cp;) put(*cp++);
+               }
+               putpage();
+               if (ntflg==0)
+                       while(line<length)
+                               put('\n');
+               page++;
+       }
+       fclose(file);
+       ncol = sncol;
+       header = sheader;
+}
+
+int main(int argc, char *argv[])
+{
+       int nfdone;
+
+       setbuf(stdout, obuf);
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+               signal(SIGINT, onintr);
+       lastarg = &argv[argc-1];
+       fixtty();
+       for (nfdone=0; argc>1; argc--) {
+               argv++;
+               if (**argv == '-') {
+                       switch (*++*argv) {
+                       case 'h':
+                               if (argc>=2) {
+                                       header = *++argv;
+                                       argc--;
+                               }
+                               continue;
+
+                       case 't':
+                               ntflg++;
+                               continue;
+
+                       case 'l':
+                               length = atoi(++*argv);
+                               continue;
+
+                       case 'w':
+                               width = atoi(++*argv);
+                               continue;
+
+                       case 's':
+                               if (*++*argv)
+                                       tabc = **argv;
+                               else
+                                       tabc = '\t';
+                               continue;
+
+                       case 'm':
+                               mflg++;
+                               continue;
+
+                       default:
+                               ncol = atoi(*argv);
+                               continue;
+                       }
+               } else if (**argv == '+') {
+                       fpage = atoi(++*argv);
+               } else {
+                       print(*argv, argv);
+                       nfdone++;
+                       if (mflg)
+                               break;
+               }
+       }
+       if (nfdone==0)
+               print((char *)0, (char **)0);
+       done();
+}
diff --git a/Applications/V7/cmd/ptx.c b/Applications/V7/cmd/ptx.c
new file mode 100644 (file)
index 0000000..ed28aa5
--- /dev/null
@@ -0,0 +1,547 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied for FUZIX */
+
+/*     permuted title index
+       ptx [-t] [-i ignore] [-o only] [-w num] [-f] [input] [output]
+       Ptx reads the input file and permutes on words in it.
+       It excludes all words in the ignore file.
+       Alternately it includes words in the only file.
+       if neither is given it excludes the words in /usr/lib/eign.
+
+       The width of the output line can be changed to num
+       characters.  If omitted 72 is default unless troff than 100.
+       the -f flag tells the program to fold the output
+       the -t flag says the output is for troff and the
+       output is then wider.
+
+\e      make: cc ptx.c -lS
+       */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <signal.h>
+#define DEFLTX "/usr/lib/eign"
+#define TILDE 0177
+#define SORT "/bin/sort"
+#define        N 30
+#define        MAX     N*BUFSIZ
+#define LMAX   200
+#define MAXT   2048
+#define MASK   03777
+#define SET    1
+
+#define isabreak(c) (btable[c])
+
+int status;
+char *hasht[MAXT];
+char line[LMAX];
+char btable[128];
+int ignore;
+int only;
+int llen = 72;
+int gap = 3;
+int gutter = 3;
+int mlen = LMAX;
+int wlen;
+int rflag;
+int halflen;
+char *strtbufp, *endbufp;
+char *empty = "";
+
+const char *infile;
+FILE *inptr = stdin;
+
+const char *outfile;
+FILE *outptr = stdout;
+
+char *sortfile;                        /* output of sort program */
+char nofold[] = { '-', 'd', 't', TILDE, 0 };
+char fold[] = { '-', 'd', 'f', 't', TILDE, 0 };
+
+char *sortopt = nofold;
+FILE *sortptr;
+
+const char *bfile;             /*contains user supplied break chars */
+FILE *bptr;
+
+
+void msg(const char *s, const char *arg)
+{
+       fprintf(stderr, "%s %s\n", s, arg);
+       return;
+}
+
+void diag(const char *s, const char *arg)
+{
+
+       msg(s, arg);
+       exit(1);
+}
+
+
+char *getline(void)
+{
+
+       register c;
+       register char *linep;
+       char *endlinep;
+
+
+       endlinep = line + mlen;
+       linep = line;
+       /* Throw away leading white space */
+
+       while (isspace(c = getc(inptr)));
+       if (c == EOF)
+               return (0);
+       ungetc(c, inptr);
+       while ((c = getc(inptr)) != EOF) {
+               switch (c) {
+
+               case '\t':
+                       if (linep < endlinep)
+                               *linep++ = ' ';
+                       break;
+               case '\n':
+                       while (isspace(*--linep));
+                       *++linep = '\n';
+                       return (linep);
+               default:
+                       if (linep < endlinep)
+                               *linep++ = c;
+               }
+       }
+       return (0);
+}
+
+void putline(char *strt, char *end)
+{
+       char *cp;
+
+       for (cp = strt; cp < end; cp++)
+               putc(*cp, sortptr);
+       /* Add extra blank before TILDE to sort correctly
+          with -fd option */
+       putc(' ', sortptr);
+       putc(TILDE, sortptr);
+       for (cp = line; cp < strt; cp++)
+               putc(*cp, sortptr);
+       putc('\n', sortptr);
+}
+
+
+int cmpword(char *cpp, char *pend, char *hpp)
+{
+       char c;
+
+       while (*hpp != '\0') {
+               c = *cpp++;
+               if ((isupper(c) ? tolower(c) : c) != *hpp++)
+                       return (0);
+       }
+       if (--cpp == pend)
+               return (1);
+       return (0);
+}
+
+int hash(char *strtp, char *endp)
+{
+       char *cp, c;
+       int i, j, k;
+
+       /* Return zero hash number for single letter words */
+       if ((endp - strtp) == 1)
+               return (0);
+
+       cp = strtp;
+       c = *cp++;
+       i = (isupper(c) ? tolower(c) : c);
+       c = *cp;
+       j = (isupper(c) ? tolower(c) : c);
+       i = i * j;
+       cp = --endp;
+       c = *cp--;
+       k = (isupper(c) ? tolower(c) : c);
+       c = *cp;
+       j = (isupper(c) ? tolower(c) : c);
+       j = k * j;
+
+       k = (i ^ (j >> 2)) & MASK;
+       return (k);
+}
+
+
+void cmpline(char *pend)
+{
+
+       char *pstrt, *pchar, *cp;
+       char **hp;
+       int flag;
+
+       pchar = line;
+       if (rflag)
+               while (pchar < pend && !isspace(*pchar))
+                       pchar++;
+       while (pchar < pend) {
+               /* eliminate white space */
+               if (isabreak(*pchar++))
+                       continue;
+               pstrt = --pchar;
+
+               flag = 1;
+               while (flag) {
+                       if (isabreak(*pchar)) {
+                               hp = &hasht[hash(pstrt, pchar)];
+                               pchar--;
+                               while (cp = *hp++) {
+                                       if (hp == &hasht[MAXT])
+                                               hp = hasht;
+                                       /* possible match */
+                                       if (cmpword(pstrt, pchar, cp)) {
+                                               /* exact match */
+                                               if (!ignore && only)
+                                                       putline(pstrt,
+                                                               pend);
+                                               flag = 0;
+                                               break;
+                                       }
+                               }
+                               /* no match */
+                               if (flag) {
+                                       if (ignore || !only)
+                                               putline(pstrt, pend);
+                                       flag = 0;
+                               }
+                       }
+                       pchar++;
+               }
+       }
+}
+
+
+char *rtrim(char *a, char *c, int d)
+{
+       char *b, *x;
+       b = c;
+       for (x = a + 1; x <= c && x - a <= d; x++)
+               if ((x == c || isspace(x[0])) && !isspace(x[-1]))
+                       b = x;
+       if (b < c && !isspace(b[0]))
+               b++;
+       return (b);
+}
+
+char *ltrim(char *c, char *b, int d)
+{
+       char *a, *x;
+       a = c;
+       for (x = b - 1; x >= c && b - x <= d; x--)
+               if (!isspace(x[0]) && (x == c || isspace(x[-1])))
+                       a = x;
+       if (a > c && !isspace(a[-1]))
+               a--;
+       return (a);
+}
+
+void putout(char *strt, char *end)
+{
+       char *cp;
+
+       cp = strt;
+
+       for (cp = strt; cp < end; cp++) {
+               putc(*cp, outptr);
+       }
+}
+
+void getsort(void)
+{
+       register c;
+       register char *tilde, *linep, *ref;
+       char *p1a, *p1b, *p2a, *p2b, *p3a, *p3b, *p4a, *p4b;
+       int w;
+
+       if ((sortptr = fopen(sortfile, "r")) == NULL)
+               diag("Cannot open sorted data:", sortfile);
+
+       halflen = (llen - gutter) / 2;
+       linep = line;
+       while ((c = getc(sortptr)) != EOF) {
+               switch (c) {
+
+               case TILDE:
+                       tilde = linep;
+                       break;
+
+               case '\n':
+                       while (isspace(linep[-1]))
+                               linep--;
+                       ref = tilde;
+                       if (rflag) {
+                               while (ref < linep && !isspace(*ref))
+                                       ref++;
+                               *ref++ = 0;
+                       }
+                       /* the -1 is an overly conservative test to leave
+                          space for the / that signifies truncation */
+                       p3b = rtrim(p3a = line, tilde, halflen - 1);
+                       if (p3b - p3a > halflen - 1)
+                               p3b = p3a + halflen - 1;
+                       p2a = ltrim(ref, p2b = linep, halflen - 1);
+                       if (p2b - p2a > halflen - 1)
+                               p2a = p2b - halflen - 1;
+                       p1b = rtrim(p1a =
+                                   p3b + (isspace(p3b[0]) != 0), tilde,
+                                   w = halflen - (p2b - p2a) - gap);
+                       if (p1b - p1a > w)
+                               p1b = p1a;
+                       p4a = ltrim(ref, p4b =
+                                   p2a - (isspace(p2a[-1]) != 0), w =
+                                   halflen - (p3b - p3a) - gap);
+                       if (p4b - p4a > w)
+                               p4a = p4b;
+                       fprintf(outptr, ".xx \"");
+                       putout(p1a, p1b);
+                       /* tilde-1 to account for extra space before TILDE */
+                       if (p1b != (tilde - 1) && p1a != p1b)
+                               fprintf(outptr, "/");
+                       fprintf(outptr, "\" \"");
+                       if (p4a == p4b && p2a != ref && p2a != p2b)
+                               fprintf(outptr, "/");
+                       putout(p2a, p2b);
+                       fprintf(outptr, "\" \"");
+                       putout(p3a, p3b);
+                       /* ++p3b to account for extra blank after TILDE */
+                       /* ++p3b to account for extra space before TILDE */
+                       if (p1a == p1b && ++p3b != tilde)
+                               fprintf(outptr, "/");
+                       fprintf(outptr, "\" \"");
+                       if (p1a == p1b && p4a != ref && p4a != p4b)
+                               fprintf(outptr, "/");
+                       putout(p4a, p4b);
+                       if (rflag)
+                               fprintf(outptr, "\" %s\n", tilde);
+                       else
+                               fprintf(outptr, "\"\n");
+                       linep = line;
+                       break;
+
+               case '"':
+                       /* put double " for "  */
+                       *linep++ = c;
+               default:
+                       *linep++ = c;
+               }
+       }
+}
+
+void onintr(int sig)
+{
+
+       if (*sortfile)
+               unlink(sortfile);
+       exit(sig ? 1 : 0);
+}
+
+int storeh(int num, char *strtp)
+{
+       int i;
+
+       for (i = num; i < MAXT; i++) {
+               if (hasht[i] == 0) {
+                       hasht[i] = strtp;
+                       return (0);
+               }
+       }
+       for (i = 0; i < num; i++) {
+               if (hasht[i] == 0) {
+                       hasht[i] = strtp;
+                       return (0);
+               }
+       }
+       return (1);
+}
+
+int main(int argc, const char *argv[])
+{
+       register int c;
+       register char *bufp;
+       pid_t pid;
+       char *pend;
+       int fd;
+
+       const char *xfile;
+       FILE *xptr;
+
+       if (signal(SIGHUP, onintr) == SIG_IGN)
+               signal(SIGHUP, SIG_IGN);
+       if (signal(SIGINT, onintr) == SIG_IGN)
+               signal(SIGINT, SIG_IGN);
+       signal(SIGPIPE, onintr);
+       signal(SIGTERM, onintr);
+
+/*     argument decoding       */
+
+       xfile = DEFLTX;
+       argv++;
+       while (argc > 1 && **argv == '-') {
+               switch (*++*argv) {
+
+               case 'r':
+                       rflag++;
+                       break;
+               case 'f':
+                       sortopt = fold;
+                       break;
+
+               case 'w':
+                       if (argc >= 2) {
+                               argc--;
+                               wlen++;
+                               llen = atoi(*++argv);
+                               if (llen == 0)
+                                       diag("Wrong width:", *argv);
+                               if (llen > LMAX) {
+                                       llen = LMAX;
+                                       msg("Lines truncated to 200 chars.", empty);
+                               }
+                               break;
+                       }
+
+               case 't':
+                       if (wlen == 0)
+                               llen = 100;
+                       break;
+               case 'g':
+                       if (argc >= 2) {
+                               argc--;
+                               gap = gutter = atoi(*++argv);
+                       }
+                       break;
+
+               case 'i':
+                       if (only)
+                               diag("Only file already given.", empty);
+                       if (argc >= 2) {
+                               argc--;
+                               ignore++;
+                               xfile = *++argv;
+                       }
+                       break;
+
+               case 'o':
+                       if (ignore)
+                               diag("Ignore file already given", empty);
+                       if (argc >= 2) {
+                               only++;
+                               argc--;
+                               xfile = *++argv;
+                       }
+                       break;
+
+               case 'b':
+                       if (argc >= 2) {
+                               argc--;
+                               bfile = *++argv;
+                       }
+                       break;
+
+               default:
+                       msg("Illegal argument:", *argv);
+               }
+               argc--;
+               argv++;
+       }
+
+       if (argc > 3)
+               diag("Too many filenames", empty);
+       else if (argc == 3) {
+               infile = *argv++;
+               outfile = *argv;
+               if ((outptr = fopen(outfile, "w")) == NULL)
+                       diag("Cannot open output file:", outfile);
+       } else if (argc == 2) {
+               infile = *argv;
+               outfile = 0;
+       }
+
+
+       /* Default breaks of blank, tab and newline */
+       btable[' '] = SET;
+       btable['\t'] = SET;
+       btable['\n'] = SET;
+       if (bfile) {
+               if ((bptr = fopen(bfile, "r")) == NULL)
+                       diag("Cannot open break char file", bfile);
+
+               while ((c = getc(bptr)) != EOF)
+                       btable[c] = SET;
+       }
+
+/*     Allocate space for a buffer.  If only or ignore file present
+       read it into buffer. Else read in default ignore file
+       and put resulting words in buffer.
+       */
+
+
+       if ((strtbufp = calloc(N, BUFSIZ)) == NULL)
+               diag("Out of memory space", empty);
+       bufp = strtbufp;
+       endbufp = strtbufp + MAX;
+
+       if ((xptr = fopen(xfile, "r")) == NULL)
+               diag("Cannot open  file", xfile);
+
+       while (bufp < endbufp && (c = getc(xptr)) != EOF) {
+               if (isabreak(c)) {
+                       if (storeh(hash(strtbufp, bufp), strtbufp))
+                               diag("Too many words", xfile);
+                       *bufp++ = '\0';
+                       strtbufp = bufp;
+               } else {
+                       *bufp++ = (isupper(c) ? tolower(c) : c);
+               }
+       }
+       if (bufp >= endbufp)
+               diag("Too many words in file", xfile);
+       endbufp = --bufp;
+
+       /* open output file for sorting */
+
+       sortfile = tmpnam("ptxsXXXXX");
+       fd = open(sortfile, O_CREAT | O_EXCL | O_WRONLY, 0600);
+       if (fd < 0)
+               diag("Cannot open output for sorting:", sortfile);
+       sortptr = fdopen(fd, "w");
+
+/*     get a line of data and compare each word for
+       inclusion or exclusion in the sort phase
+*/
+
+       if (infile != 0 && (inptr = fopen(infile, "r")) == NULL)
+               diag("Cannot open data: ", infile);
+       while (pend = getline())
+               cmpline(pend);
+       fclose(sortptr);
+
+       switch (pid = fork()) {
+
+       case -1:                /* cannot fork */
+               diag("Cannot fork", empty);
+
+       case 0:         /* child */
+               execl(SORT, SORT, sortopt, "+0", "-1", "+1",
+                     sortfile, "-o", sortfile, 0);
+
+       default:                /* parent */
+               while (wait(&status) != pid);
+       }
+
+
+       getsort();
+       onintr(0);
+}
diff --git a/Applications/V7/games/arithmetic.c b/Applications/V7/games/arithmetic.c
new file mode 100644 (file)
index 0000000..6d49b7e
--- /dev/null
@@ -0,0 +1,204 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied and defloated for FUZIX */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+
+#define        MAX     100
+
+char types[10];
+int right[MAX];
+int left[MAX];
+int rights;
+int wrongs;
+time_t stvec;
+time_t etvec;
+time_t dtvec;
+
+
+void getline(char *s)
+{
+       register char *rs;
+
+       rs = s;
+
+       while ((*rs = getchar()) == ' ');
+       while (*rs != '\n')
+               if (*rs == 0)
+                       exit(0);
+               else if (rs >= &s[99]) {
+                       while ((*rs = getchar()) != '\n')
+                               if (*rs == '\0')
+                                       exit(0);
+               } else
+                       *++rs = getchar();
+       while (*--rs == ' ')
+               *rs = '\n';
+}
+
+int getnum(char *s)
+{
+       int a;
+       char c;
+
+       a = 0;
+       while ((c = *s++) >= '0' && c <= '9') {
+               a = a * 10 + c - '0';
+       }
+       return (a);
+}
+
+
+int random(int range)
+{
+       return (rand() % range);
+}
+
+int skrand(int range)
+{
+       int temp;
+       temp = random(range) + random(range);
+       if (temp > range - 1)
+               temp = 2 * range - 1 - temp;
+       return (temp);
+}
+
+void score(void)
+{
+       long l;
+       time(&etvec);
+
+       printf("\n\nRights %d; Wrongs %d; Score %d%%\n", rights, wrongs,
+              (rights * 100) / (rights + wrongs));
+
+       if (rights == 0)
+               return;
+
+       l = etvec - stvec;
+
+       printf("Total time %ld seconds; %d.%2d seconds per problem\n\n\n",
+              l, l / rights, ((l * 100) / rights)%100);
+
+       sleep(3);
+       time(&dtvec);
+       stvec += dtvec - etvec;
+}
+
+void delete(int sig)
+{
+       if (rights + wrongs == 0.) {
+               printf("\n");
+               exit(0);
+       }
+       score();
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       int range, k, dif, l;
+       char line[100];
+       int ans, pans, i, j, t;
+
+       signal(SIGINT, delete);
+
+       range = 11;
+       dif = 0;
+       while (argc > 1) {
+               switch (*argv[1]) {
+               case '+':
+               case '-':
+               case 'x':
+               case '/':
+                       while (types[dif] = argv[1][dif])
+                               dif++;
+                       break;
+
+               default:
+                       range = getnum(argv[1]) + 1;
+               }
+               argv++;
+               argc--;
+       }
+       if (range > MAX) {
+               printf("Range is too large.\n");
+               exit(0);
+       }
+
+       if (dif == 0) {
+               types[0] = '+';
+               types[1] = '-';
+               dif = 2;
+       }
+
+       for (i = 0; i < range; i++) {
+               left[i] = right[i] = i;
+       }
+       time(&stvec);
+       k = stvec;
+       srand(k);
+       k = 0;
+       l = 0;
+       goto start;
+
+      loop:
+       if (++k % 20 == 0)
+               score();
+
+      start:
+       i = skrand(range);
+       j = skrand(range);
+       if (dif > 1)
+               l = random(dif);
+
+       switch (types[l]) {
+       case '+':
+       default:
+               ans = left[i] + right[j];
+               printf("%d + %d =   ", left[i], right[j]);
+               break;
+
+       case '-':
+               t = left[i] + right[j];
+               ans = left[i];
+               printf("%d - %d =   ", t, right[j]);
+               break;
+
+       case 'x':
+               ans = left[i] * right[j];
+               printf("%d x %d =   ", left[i], right[j]);
+               break;
+
+       case '/':
+               while (right[j] == 0)
+                       j = random(range);
+               t = left[i] * right[j] + random(right[j]);
+               ans = left[i];
+               printf("%d / %d =   ", t, right[j]);
+               break;
+       }
+
+
+      loop1:
+       getline(line);
+       dtvec += etvec - stvec;
+       if (line[0] == '\n')
+               goto loop1;
+       pans = getnum(line);
+       if (pans == ans) {
+               printf("Right!\n");
+               rights++;
+               goto loop;
+       } else {
+               printf("What?\n");
+               wrongs++;
+               if (range >= MAX)
+                       goto loop1;
+               left[range] = left[i];
+               right[range++] = right[j];
+               goto loop1;
+       }
+}
diff --git a/Applications/V7/games/backgammon.c b/Applications/V7/games/backgammon.c
new file mode 100644 (file)
index 0000000..8cd1122
--- /dev/null
@@ -0,0 +1,670 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* ANSIfied and some PDP11isms and bugs fixed for FUZIX */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define NIL (-1)
+#define MAXGMOV 10
+#define MAXIMOVES 1000
+
+char level;                    /*'b'=beginner, 'i'=intermediate, 'e'=expert */
+int die1;
+int die2;
+int i;
+int j;
+int l;
+int m;
+int count;
+int red[] = { 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
+       0, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0
+};
+
+int white[] = { 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
+       0, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0
+};
+
+int probability[] = { 0, 11, 12, 13, 14, 15, 16,
+       06, 05, 04, 03, 02, 01
+};
+
+int imoves;
+int goodmoves[MAXGMOV];
+int probmoves[MAXGMOV];
+struct {
+       int pos[4], mov[4];
+} moves[MAXIMOVES];
+
+
+void getstr(char *s)
+{
+       while ((*s = getchar()) != '\n')
+               s++;
+       *s = 0;
+}
+
+int piececount(int *player, int startrow, int endrow)
+{
+       int sum;
+       sum = 0;
+       while (startrow <= endrow)
+               sum += player[startrow++];
+       return (sum);
+}
+
+int play(int *player, int *playee, int pos[])
+{
+       int k, n, die, ipos;
+       for (k = 0; k < player[0]; k++) {       /*blots on player[0] must be moved first */
+               if (pos[k] == NIL)
+                       break;
+               if (pos[k] != 0) {
+                       printf
+                           ("piece on position 0 must be moved first\n");
+                       return (-1);
+               }
+       }
+       for (k = 0; (ipos = pos[k]) != NIL; k++) {
+               die = k ? die2 : die1;
+               n = 25 - ipos - die;
+               if (player[ipos] == 0)
+                       goto badmove;
+               if (n > 0 && playee[n] >= 2)
+                       goto badmove;
+               if (n <= 0) {
+                       if (piececount(player, 0, 18) != 0)
+                               goto badmove;
+                       if ((ipos + die) != 25 &&
+                           piececount(player, 19, 24 - die) != 0)
+                               goto badmove;
+               }
+               player[ipos]--;
+               player[ipos + die]++;
+       }
+       for (k = 0; pos[k] != NIL; k++) {
+               die = k ? die2 : die1;
+               n = 25 - pos[k] - die;
+               if (n > 0 && playee[n] == 1) {
+                       playee[n] = 0;
+                       playee[0]++;
+               }
+       }
+       return (0);
+
+      badmove:
+       printf("Move %d is not legal.\n", ipos);
+       while (k--) {
+               die = k ? die2 : die1;
+               player[pos[k]]++;
+               player[pos[k] + die]--;
+       }
+       return (-1);
+}
+
+
+void prtmov(int k)
+{
+       int n;
+       if (k == NIL)
+               printf("no move possible\n");
+       else
+               for (n = 0; n < 4; n++) {
+                       if (moves[k].pos[n] == NIL)
+                               break;
+                       printf("    %d, %d", 25 - moves[k].pos[n],
+                              moves[k].mov[n]);
+               }
+       printf("\n");
+}
+
+void update(int *player, int *playee, int k)
+{
+       int n, t;
+       for (n = 0; n < 4; n++) {
+               if (moves[k].pos[n] == NIL)
+                       break;
+               player[moves[k].pos[n]]--;
+               player[moves[k].pos[n] + moves[k].mov[n]]++;
+               t = 25 - moves[k].pos[n] - moves[k].mov[n];
+               if (t > 0 && playee[t] == 1) {
+                       playee[0]++;
+                       playee[t]--;
+               }
+       }
+}
+
+/*
+void prtmovs(void)
+{
+       int i1,i2;
+       printf( "possible moves are\n");
+       for(i1=0;i1<imoves;i1++){
+               printf( "\n%d",i1);
+               for(i2=0;i2<4;i2++){
+                       if(moves[i1].pos[i2]==NIL)break;
+                       printf( "%d, %d",moves[i1].pos[i2],moves[i1].mov[i2]);
+               }
+       }
+       printf( "\n");
+}
+*/
+
+void roll(void)
+{
+       extern int die1, die2;
+       die1 = (rand() >> 8) % 6 + 1;
+       die2 = (rand() >> 8) % 6 + 1;
+}
+
+void moverecord(int *mover)
+{
+       extern int i, j, l, m, imoves, count;
+       int t;
+       if (imoves >= MAXIMOVES)
+               goto undo;;
+       for (t = 0; t <= 3; t++)
+               moves[imoves].pos[t] = NIL;
+       switch (count) {
+       case 4:
+               moves[imoves].pos[3] = m;
+               moves[imoves].mov[3] = die1;
+       case 3:
+               moves[imoves].pos[2] = l;
+               moves[imoves].mov[2] = die1;
+       case 2:
+               moves[imoves].pos[1] = j;
+               moves[imoves].mov[1] = die2;
+       case 1:
+               moves[imoves].pos[0] = i;
+               moves[imoves].mov[0] = die1;
+               imoves++;
+       }
+      undo:
+       switch (count) {
+       case 4:
+               break;
+       case 3:
+               mover[l]++;
+               mover[l + die1]--;
+               break;
+       case 2:
+               mover[j]++;
+               mover[j + die2]--;
+               break;
+       case 1:
+               mover[i]++;
+               mover[i + die1]--;
+       }
+}
+
+void movegen(int *mover, int *movee)
+{
+       extern int i, j, l, m, count;
+       extern int die1, die2;
+       int k;
+       for (i = 0; i <= 24; i++) {
+               count = 0;
+               if (mover[i] == 0)
+                       continue;
+               if ((k = 25 - i - die1) > 0 && movee[k] >= 2)
+                       if (mover[0] > 0)
+                               break;
+                       else
+                               continue;
+               if (k <= 0) {
+                       if (piececount(mover, 0, 18) != 0)
+                               break;
+                       if ((i + die1) != 25 &&
+                           piececount(mover, 19, 24 - die1) != 0)
+                               break;
+               }
+               mover[i]--;
+               mover[i + die1]++;
+               count = 1;
+               for (j = 0; j <= 24; j++) {
+                       if (mover[j] == 0)
+                               continue;
+                       if ((k = 25 - j - die2) > 0 && movee[k] >= 2)
+                               if (mover[0] > 0)
+                                       break;
+                               else
+                                       continue;
+                       if (k <= 0) {
+                               if (piececount(mover, 0, 18) != 0)
+                                       break;
+                               if ((j + die2) != 25 &&
+                                   piececount(mover, 19, 24 - die2) != 0)
+                                       break;
+                       }
+                       mover[j]--;
+                       mover[j + die2]++;
+                       count = 2;
+                       if (die1 != die2) {
+                               moverecord(mover);
+                               if (mover[0] > 0)
+                                       break;
+                               else
+                                       continue;
+                       }
+                       for (l = 0; l <= 24; l++) {
+                               if (mover[l] == 0)
+                                       continue;
+                               if ((k = 25 - l - die1) > 0
+                                   && movee[k] >= 2)
+                                       if (mover[0] > 0)
+                                               break;
+                                       else
+                                               continue;
+                               if (k <= 0) {
+                                       if (piececount(mover, 0, 18) != 0)
+                                               break;
+                                       if ((l + die2) != 25 &&
+                                           piececount(mover, 19,
+                                                      24 - die1) != 0)
+                                               break;
+                               }
+                               mover[l]--;
+                               mover[l + die1]++;
+                               count = 3;
+                               for (m = 0; m <= 24; m++) {
+                                       if (mover[m] == 0)
+                                               continue;
+                                       if ((k = 25 - m - die1) >= 0
+                                           && movee[k] >= 2)
+                                               if (mover[0] > 0)
+                                                       break;
+                                               else
+                                                       continue;
+                                       if (k <= 0) {
+                                               if (piececount
+                                                   (mover, 0, 18) != 0)
+                                                       break;
+                                               if ((m + die2) != 25 &&
+                                                   piececount(mover, 19,
+                                                              24 -
+                                                              die1) != 0)
+                                                       break;
+                                       }
+                                       count = 4;
+                                       moverecord(mover);
+                                       if (mover[0] > 0)
+                                               break;
+                               }
+                               if (count == 3)
+                                       moverecord(mover);
+                               else {
+                                       mover[l]++;
+                                       mover[l + die1]--;
+                               }
+                               if (mover[0] > 0)
+                                       break;
+                       }
+                       if (count == 2)
+                               moverecord(mover);
+                       else {
+                               mover[j]++;
+                               mover[j + die1]--;
+                       }
+                       if (mover[0] > 0)
+                               break;
+               }
+               if (count == 1)
+                       moverecord(mover);
+               else {
+                       mover[i]++;
+                       mover[i + die1]--;
+               }
+               if (mover[0] > 0)
+                       break;
+       }
+}
+
+int getprob(int *player, int *playee, int start, int finish)
+{                              /*returns the probability (times 102) that any
+                                  pieces belonging to 'player' and lying between
+                                  his points 'start' and 'finish' will be hit
+                                  by a piece belonging to playee
+                                */
+       int k, n, sum;
+       sum = 0;
+       for (; start <= finish; start++) {
+               if (player[start] == 1) {
+                       for (k = 1; k <= 12; k++) {
+                               if ((n = 25 - start - k) < 0)
+                                       break;
+                               if (playee[n] != 0)
+                                       sum += probability[k];
+                       }
+               }
+       }
+       return (sum);
+}
+
+int eval(int *player, int *playee, int k, int *prob)
+{
+       extern char level;
+       int newtry[31], newother[31], *r, *q, *p, n, sum, first;
+       int ii, lastwhite, lastred;
+       *prob = sum = 0;
+       r = player + 25;
+       p = newtry;
+       q = newother;
+       while (player < r) {
+               *p++ = *player++;
+               *q++ = *playee++;
+       }
+       q = newtry + 31;
+       for (p = newtry + 25; p < q;)
+               *p++ = 0;       /*zero out spaces for hit pieces */
+       for (n = 0; n < 4; n++) {
+               if (moves[k].pos[n] == NIL)
+                       break;
+               newtry[moves[k].pos[n]]--;
+               newtry[ii = moves[k].pos[n] + moves[k].mov[n]]++;
+               if (ii < 25 && newother[25 - ii] == 1) {
+                       newother[25 - ii] = 0;
+                       newother[0]++;
+                       if (ii <= 15 && level == 'e')
+                               sum++;  /*hit if near other's home */
+               }
+       }
+       for (lastred = 0; newother[lastred] == 0; lastred++);
+       for (lastwhite = 0; newtry[lastwhite] == 0; lastwhite++);
+       lastwhite = 25 - lastwhite;
+       if (lastwhite <= 6 && lastwhite < lastred)
+               sum = 1000;
+       if (lastwhite < lastred && level == 'e' && lastwhite > 6) {     /*expert's running game.
+                                                                          First priority to get all
+                                                                          pieces into white's home */
+               for (sum = 1000; lastwhite > 6; lastwhite--)
+                       sum = sum - lastwhite * newtry[25 - lastwhite];
+       }
+       for (first = 0; first < 25; first++)
+               if (newother[first] != 0)
+                       break;  /*find other's first piece */
+       q = newtry + 25;
+       for (p = newtry + 1; p < q;)
+               if (*p++ > 1)
+                       sum++;  /*blocked points are good */
+       if (first > 5) {        /*only stress removing pieces if homeboard
+                                  cannot be hit
+                                */
+               q = newtry + 31;
+               p = newtry + 25;
+               for (n = 6; p < q; n--)
+                       sum += *p++ * n;        /*remove pieces, but just barely */
+       }
+       if (level != 'b') {
+               r = newtry + 25 - first;        /*singles past this point can't be hit */
+               for (p = newtry + 7; p < r;)
+                       if (*p++ == 1)
+                               sum--;  /*singles are bad after 1st 6 points
+                                          if they can be hit */
+               q = newtry + 3;
+               for (p = newtry; p < q;)
+                       sum -= *p++;    /*bad to be on 1st three points */
+       }
+
+       for (n = 1; n <= 4; n++)
+               *prob += n * getprob(newtry, newother, 6 * n - 5, 6 * n);
+       return (sum);
+}
+
+int strategy(int *player, int *playee)
+{
+       extern char level;
+       int k, n, nn, bestval, moveval, prob;
+       n = 0;
+       if (imoves == 0)
+               return (NIL);
+       goodmoves[0] = NIL;
+       bestval = -32000;
+       for (k = 0; k < imoves; k++) {
+               if ((moveval = eval(player, playee, k, &prob)) < bestval)
+                       continue;
+               if (moveval > bestval) {
+                       bestval = moveval;
+                       n = 0;
+               }
+               if (n < MAXGMOV) {
+                       goodmoves[n] = k;
+                       probmoves[n++] = prob;
+               }
+       }
+       if (level == 'e' && n > 1) {
+               nn = n;
+               n = 0;
+               prob = 32000;
+               for (k = 0; k < nn; k++) {
+                       if ((moveval = probmoves[k]) > prob)
+                               continue;
+                       if (moveval < prob) {
+                               prob = moveval;
+                               n = 0;
+                       }
+                       goodmoves[n] = goodmoves[k];
+                       probmoves[n++] = probmoves[k];
+               }
+       }
+       return (goodmoves[(rand() >> 4) % n]);
+}
+
+int nextmove(int *player, int *playee)
+{
+       int k;
+       imoves = 0;
+       movegen(player, playee);
+       if (die1 != die2) {
+               k = die1;
+               die1 = die2;
+               die2 = k;
+               movegen(player, playee);
+       }
+       if (imoves == 0) {
+               printf("roll was %d,%d; no white move possible\n", die1,
+                      die2);
+               return (NIL);
+       }
+       k = strategy(player, playee);   /*select kth possible move */
+       prtmov(k);
+       update(player, playee, k);
+       return (0);
+}
+
+
+
+
+
+void instructions(void)
+{
+       printf("To play backgammon, type the numbers of the points\n");
+       printf("from which pieces are to be moved. Thus, if the\n");
+       printf("roll is '3,5', typing '2 6' will move a piece\n");
+       printf("from point 2 three spaces to point 5,\n");
+       printf("and a piece from point 6 forward to\n");
+       printf("point 11.  If the moves must be made in the\n");
+       printf("opposite order, the first character typed must\n");
+       printf("be a minus ('-'). Thus, typing\n");
+       printf("'-2 6' moves the piece on point 2\n");
+       printf("by 5, and the piece on point 6 by 3.\n");
+       printf("If you want to move a single piece several times,\n");
+       printf("the sequence of points from which it is to be\n");
+       printf("moved must be typed. Thus '14 17' will move\n");
+       printf("a piece from point 14 to point 17 and thence to\n");
+       printf("to point 22.\n");
+       printf("If a double is rolled, you should type four numbers.\n");
+       printf("Red pieces that have been removed from the board by\n");
+       printf("being hit by white are on point 0 and\n");
+       printf("must be brought in before any other move can be made.\n");
+       printf("White pieces that are hit are removed to point 25.\n");
+       printf("You will not be allowed to make an illegal move, or\n");
+       printf("to make too many moves. However, if you make too\n");
+       printf("few moves, the program does not care. In particular\n");
+       printf("you may skip your turn by typing a 'new-line'\n");
+       printf("all by itself.\n\n");
+}
+
+
+void numline(int *upcol, int *downcol, int start, int fin)
+{
+       int k, n;
+       for (k = start; k <= fin; k++) {
+               if ((n = upcol[k]) != 0 || (n = downcol[25 - k]) != 0)
+                       printf("%4d", n);
+               else
+                       printf("    ");
+       }
+}
+
+void colorline(int *upcol, char c1, int *downcol, char c2, int start,
+              int fin)
+{
+       int k;
+       char c;
+       for (k = start; k <= fin; k++) {
+               c = ' ';
+               if (upcol[k] != 0)
+                       c = c1;
+               if (downcol[25 - k] != 0)
+                       c = c2;
+               printf("   %c", c);
+       }
+}
+
+
+void prtbrd(void)
+{
+       int k;
+       printf("White's Home\n");
+       for (k = 1; k <= 6; k++)
+               printf("%4d", k);
+       printf("    ");
+       for (k = 7; k <= 12; k++)
+               printf("%4d", k);
+       putchar('\r');
+       for (k = 1; k <= 54; k++)
+               putchar('_');
+       putchar('\n');
+       numline(red, white, 1, 6);
+       printf("    ");
+       numline(red, white, 7, 12);
+       putchar('\n');
+       colorline(red, 'R', white, 'W', 1, 6);
+       printf("    ");
+       colorline(red, 'R', white, 'W', 7, 12);
+       putchar('\n');
+       if (white[0] != 0)
+               printf("%28dW\n", white[0]);
+       else
+               putchar('\n');
+       if (red[0] != 0)
+               printf("%28dR\n", red[0]);
+       else
+               putchar('\n');
+       colorline(white, 'W', red, 'R', 1, 6);
+       printf("    ");
+       colorline(white, 'W', red, 'R', 7, 12);
+       putchar('\n');
+       numline(white, red, 1, 6);
+       printf("    ");
+       numline(white, red, 7, 12);
+       putchar('\r');
+       for (k = 1; k <= 54; k++)
+               putchar('_');
+       putchar('\n');
+       for (k = 24; k >= 19; k--)
+               printf("%4d", k);
+       printf("    ");
+       for (k = 18; k >= 13; k--)
+               printf("%4d", k);
+       printf("\nRed's Home\n\n\n\n\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+       int t, k, n, go[6];
+       char s[100];
+       go[5] = NIL;
+       printf("Do you want instructions? Type 'y' for yes,\n");
+       printf("anything else means no.?? ");
+       getstr(s);
+       if (*s == 'y')
+               instructions();
+
+       /* Set the randomness depending upon the user keyboard time */
+
+       srand(((uint16_t) time(NULL)) ^ getpid());
+       printf("Choose the level of your oppponent.\n");
+       printf("Type 'b' for beginner, or 'i' for intermediate.\n");
+       printf("Anything else gets you an expert.?? ");
+       level = 'e';
+       getstr(s);
+       if (*s == 'b')
+               level = 'b';
+       else if (*s == 'i')
+               level = 'i';
+       printf("You will play red. Do you wan't to move first?\n");
+       printf("Type 'y' for yes, anything else means no.?? ");
+       getstr(s);
+       if (*s == 'y')
+               goto nowhmove;
+      whitesmv:
+       roll();
+       printf("white rolls %d,%d\n", die1, die2);
+       printf("white's move is:");
+       if (nextmove(white, red) == NIL)
+               goto nowhmove;
+       if (piececount(white, 0, 24) == 0) {
+               printf("White wins\n");
+               printf
+                   ("Aren't you ashamed. You've been beaten by a computer.\n");
+               exit(0);
+       }
+      nowhmove:
+       prtbrd();
+
+       roll();
+      retry:
+       printf("your roll is %d,  %d\n", die1, die2);
+       printf("your move, please?? ");
+       getstr(s);
+       if (*s == 0) {
+               printf("red's move skipped\n");
+               goto whitesmv;
+       }
+       n = sscanf(s, "%d%d%d%d%d", &go[0], &go[1], &go[2], &go[3],
+                  &go[4]);
+       if ((die1 != die2 && n > 2) || n > 4) {
+               printf("you've made too many moves\n");
+               goto retry;
+       }
+       go[n] = NIL;
+       if (*s == '-') {
+               go[0] = -go[0];
+               t = die1;
+               die1 = die2;
+               die2 = t;
+       }
+       for (k = 0; k < n; k++) {
+               if (0 <= go[k] && go[k] <= 24)
+                       continue;
+               else {
+                       printf("move %d is illegal\n", go[k]);
+                       goto retry;
+               }
+       }
+       if (play(red, white, go))
+               goto retry;
+       if (piececount(red, 0, 24) == 0) {
+               printf("Red wins.\n");
+               printf
+                   ("Congratulations! You have just defeated a dumb machine.\n");
+               exit(0);
+       }
+       goto whitesmv;
+}
diff --git a/Applications/V7/games/fish.c b/Applications/V7/games/fish.c
new file mode 100644 (file)
index 0000000..5d2d607
--- /dev/null
@@ -0,0 +1,566 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Re-ordered, some bugs fixed and ANSIfied for FUZIX */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*     Through, `my' refers to the program, `your' to the player */
+
+#define CTYPE 13
+#define CTSIZ (CTYPE+1)
+#define DECK 52
+#define NOMORE 0
+#define DOUBTIT (-1);
+
+typedef char HAND[CTSIZ];
+
+/* data structures */
+
+short debug;
+
+HAND myhand;
+HAND yourhand;
+char deck[DECK];
+short nextcd;
+int proflag;
+
+/* utility and output programs */
+
+
+void error(char *s)
+{
+       fprintf(stderr, "error: ");
+       fprintf(stderr, s);
+       exit(1);
+}
+
+int choose(char a[], int n)
+{
+       /* pick and return one at random from the n choices in a */
+       /* The last one is moved to replace the one chosen */
+       register j, t;
+
+       if (n <= 0)
+               error("null choice");
+
+       j = rand() % n;
+       t = a[j];
+       a[j] = a[n - 1];
+       return (t);
+}
+
+
+void shuffle(void)
+{
+       /* shuffle the deck, and reset nextcd */
+       /* uses the random number generator `rand' in the C library */
+       /* assumes that `srand' has already been called */
+
+       register i;
+
+       for (i = 0; i < DECK; ++i)
+               deck[i] = (i % 13) + 1; /* seed the deck */
+
+       for (i = DECK; i > 0; --i) {    /* select the next card at random */
+               deck[i - 1] = choose(deck, i);
+       }
+
+       nextcd = 0;
+}
+
+int draw(void)
+{
+       if (nextcd >= DECK)
+               return (NOMORE);
+       return (deck[nextcd++]);
+}
+
+int empty(HAND h)
+{
+       register i;
+
+       for (i = 1; i <= CTYPE; ++i) {
+               if (h[i] != 0 && h[i] != 4)
+                       return (0);
+       }
+       return (i);
+}
+
+int mark(HAND hand, int cd)
+{
+       if (cd != NOMORE) {
+               ++hand[cd];
+               if (hand[cd] > 4) {
+                       error("mark overflow");
+               }
+       }
+       return (cd);
+}
+
+void deal(HAND hand, int n)
+{
+       while (n--) {
+               if (mark(hand, draw()) == NOMORE)
+                       error("deck exhausted");
+       }
+}
+
+char *cname[] = {
+       "NOMORE!!!",
+       "A",
+       "2",
+       "3",
+       "4",
+       "5",
+       "6",
+       "7",
+       "8",
+       "9",
+       "10",
+       "J",
+       "Q",
+       "K",
+};
+
+void stats(void)
+{
+       register i, ct, b;
+
+       if (proflag)
+               printf("Pro level\n");
+       b = ct = 0;
+
+       for (i = 1; i <= CTYPE; ++i) {
+               if (myhand[i] == 4)
+                       ++b;
+               else
+                       ct += myhand[i];
+       }
+
+       if (b) {
+               printf("My books: ");
+               for (i = 1; i <= CTYPE; ++i) {
+                       if (myhand[i] == 4)
+                               printf("%s ", cname[i]);
+               }
+               printf("\n");
+       }
+
+       printf("%d cards in my hand, %d in the pool\n", ct, DECK - nextcd);
+       printf("You ask me for: ");
+}
+
+void phand(HAND h)
+{
+       register i, j;
+
+       j = 0;
+
+       for (i = 1; i <= CTYPE; ++i) {
+               if (h[i] == 4) {
+                       ++j;
+                       continue;
+               }
+               if (h[i]) {
+                       register k;
+                       k = h[i];
+                       while (k--)
+                               printf("%s ", cname[i]);
+               }
+       }
+
+       if (j) {
+               printf("+ Books of ");
+               for (i = 1; i <= CTYPE; ++i) {
+                       if (h[i] == 4)
+                               printf("%s ", cname[i]);
+               }
+       }
+
+       printf("\n");
+}
+
+
+/*     print instructions */
+
+const char *inst[] = {
+       "`Go Fish' is a childrens' card game.",
+       "The Object is to accumulate `books' of 4 cards",
+       "with the same face value.",
+       "The players alternate turns; each turn begins with one",
+       "player selecting a card from his hand, and asking the",
+       "other player for all cards of that face value.",
+       "If the other player has one or more cards of that face value",
+       "in his hand, he gives them to the first player, and the",
+       "first player makes another request.",
+       "Eventually, the first player asks for a card which",
+       "is not in the second player's hand: he replies `GO FISH!'",
+       "The first player then draws a card from the `pool' of",
+       "undealt cards.  If this is the card he had last requested, he",
+       "draws again.",
+       "When a book is made, either through drawing or requesting,",
+       "the cards are laid down and no further action takes",
+       "place with that face value.",
+       "To play the computer, simply make guesses by typing",
+       "a, 2, 3, 4, 5, 6, 7, 8, 9, 10, j, q, or k when asked.",
+       "Hitting return gives you information about the size of",
+       "my hand and the pool, and tells you about my books.",
+       "Saying `p' as a first guess puts you into `pro' level;",
+       "The default is pretty dumb!",
+       "Good Luck!",
+       "",
+};
+
+void instruct(void)
+{
+       register char **cpp;
+
+       printf("\n");
+
+       for (cpp = inst; **cpp != '\0'; ++cpp) {
+               printf("%s\n", *cpp);
+       }
+}
+
+
+void madebook(int x)
+{
+       printf("Made a book of %s's\n", cname[x]);
+}
+
+void score(void)
+{
+       register my, your, i;
+
+       my = your = 0;
+
+       printf("The game is over.\nMy books: ");
+
+       for (i = 1; i <= CTYPE; ++i) {
+               if (myhand[i] == 4) {
+                       ++my;
+                       printf("%s ", cname[i]);
+               }
+       }
+
+       printf("\nYour books: ");
+
+       for (i = 1; i <= CTYPE; ++i) {
+               if (yourhand[i] == 4) {
+                       ++your;
+                       printf("%s ", cname[i]);
+               }
+       }
+
+       printf("\n\nI have %d, you have %d\n", my, your);
+
+       printf("\n%s win!!!\n", my > your ? "I" : "You");
+       exit(0);
+}
+
+#define G(x) { if(go) goto err;  else go = x; }
+
+int guess(void)
+{
+       /* get the guess from the tty and return it... */
+       register g, go;
+
+       go = 0;
+
+       for (;;) {
+               switch (g = getchar()) {
+
+               case 'p':
+               case 'P':
+                       ++proflag;
+                       continue;
+
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       G(g - '0');
+                       continue;
+
+               case 'a':
+               case 'A':
+                       G(1);
+                       continue;
+
+               case '1':
+                       G(10);
+                       continue;
+
+               case '0':
+                       if (go != 10)
+                               goto err;
+                       continue;
+
+               case 'J':
+               case 'j':
+                       G(11);
+                       continue;
+
+               case 'Q':
+               case 'q':
+                       G(12);
+                       continue;
+
+               case 'K':
+               case 'k':
+                       G(13);
+                       continue;
+
+               case '\n':
+                       if (empty(yourhand))
+                               return (NOMORE);
+                       if (go == 0) {
+                               stats();
+                               continue;
+                       }
+                       return (go);
+
+               case ' ':
+               case '\t':
+                       continue;
+
+               default:
+                     err:
+                       while (g != '\n')
+                               g = getchar();
+                       printf("what?\n");
+                       continue;
+               }
+       }
+}
+
+/*     the program's strategy appears from here to the end */
+
+char try[100];
+char ntry;
+char haveguessed[CTSIZ];
+
+char hehas[CTSIZ];
+
+void start(HAND h)
+{
+       ;
+}
+
+void hedrew(int d)
+{
+       ++hehas[d];
+}
+
+void heguessed(int d)
+{
+       ++hehas[d];
+}
+
+int myguess(void)
+{
+
+       register i, lg, t;
+
+       if (empty(myhand))
+               return (NOMORE);
+
+       /* make a list of those things which i have */
+       /* leave off any which are books */
+       /* if something is found that he has, guess it! */
+
+       ntry = 0;
+       for (i = 1; i <= CTYPE; ++i) {
+               if (myhand[i] == 0 || myhand[i] == 4)
+                       continue;
+               try[ntry++] = i;
+       }
+
+       if (!proflag)
+               goto random;
+
+       /* get ones he has, if any */
+
+       for (i = 0; i < ntry; ++i) {
+               if (hehas[try[i]]) {
+                       i = try[i];
+                       goto gotguess;
+               }
+       }
+
+       /* is there one that has never been guessed; if so, guess it */
+       lg = 101;
+       for (i = 0; i < ntry; ++i) {
+               if (haveguessed[try[i]] < lg)
+                       lg = haveguessed[try[i]];
+       }
+       /* remove all those not guessed longest ago */
+
+       t = 0;
+       for (i = 0; i < ntry; ++i) {
+               if (haveguessed[try[i]] == lg)
+                       try[t++] = try[i];
+       }
+       ntry = t;
+       if (t <= 0)
+               error("bad guessing loop");
+
+      random:
+       i = choose(try, ntry);  /* make a random choice */
+
+      gotguess:                /* do bookkeeping */
+
+       hehas[i] = 0;           /* he won't anymore! */
+       for (t = 1; t <= CTYPE; ++t) {
+               if (haveguessed[t])
+                       --haveguessed[t];
+       }
+       haveguessed[i] = 100;   /* will have guessed it */
+       return (i);
+
+}
+
+
+/*     reflect the effect of a move on the hands */
+
+int move(HAND hs, HAND ht, int g, int v)
+{
+       /* hand hs has made a guess, g, directed towards ht */
+       /* v on indicates that the guess was made by the machine */
+       register d;
+       const char *sp, *tp;
+
+       sp = tp = "I";
+       if (v)
+               tp = "You";
+       else
+               sp = "You";
+
+       if (g == NOMORE) {
+               d = draw();
+               if (d == NOMORE)
+                       score();
+               else {
+
+                       printf("Empty Hand\n");
+                       if (!v)
+                               printf("You draw %s\n", cname[d]);
+                       mark(hs, d);
+               }
+               return (0);
+       }
+
+       if (!v)
+               heguessed(g);
+
+       if (hs[g] == 0) {
+               if (v)
+                       error("Rotten Guess");
+               printf("You don't have any %s's\n", cname[g]);
+               return (1);
+       }
+
+       if (ht[g]) {            /* successful guess */
+               printf("%s have %d %s%s\n", tp, ht[g], cname[g],
+                      ht[g] > 1 ? "'s" : "");
+               hs[g] += ht[g];
+               ht[g] = 0;
+               if (hs[g] == 4)
+                       madebook(g);
+               return (1);
+       }
+
+       /* GO FISH! */
+
+       printf("%s say \"GO FISH!\"\n", tp);
+
+      newdraw:
+       d = draw();
+       if (d == NOMORE) {
+               printf("No more cards\n");
+               return (0);
+       }
+       mark(hs, d);
+       if (!v)
+               printf("You draw %s\n", cname[d]);
+       if (hs[d] == 4)
+               madebook(d);
+       if (d == g) {
+               printf("%s drew the guess, so draw again\n", sp);
+               if (!v)
+                       hedrew(d);
+               goto newdraw;
+       }
+       return (0);
+}
+
+void game(void)
+{
+
+       shuffle();
+
+       deal(myhand, 7);
+       deal(yourhand, 7);
+
+       start(myhand);
+
+       for (;;) {
+
+               register g;
+
+
+               /* you make repeated guesses */
+
+               for (;;) {
+                       printf("your hand is: ");
+                       phand(yourhand);
+                       printf("you ask me for: ");
+                       if (!move(yourhand, myhand, g = guess(), 0))
+                               break;
+                       printf("Guess again\n");
+               }
+
+               /* I make repeated guesses */
+
+               for (;;) {
+                       if ((g = myguess()) != NOMORE) {
+                               printf("I ask you for: %s\n", cname[g]);
+                       }
+                       if (!move(myhand, yourhand, g, 1))
+                               break;
+                       printf("I get another guess\n");
+               }
+       }
+}
+
+
+int main(int argc, char *argv[])
+{
+       /* initialize shuffling, ask for instructions, play game, die */
+       register int c;
+
+       if (argc > 1 && argv[1][0] == '-') {
+               while (argv[1][0] == '-') {
+                       ++argv[1];
+                       ++debug;
+               }
+               argv++;
+               argc--;
+       }
+
+
+       printf("instructions?\n");
+       if ((c = getchar()) != '\n') {
+               if (c != 'n')
+                       instruct();
+               while (getchar() != '\n');
+       }
+
+       srand(getpid() ^ ((uint16_t) time(NULL)));
+       game();
+}
diff --git a/Applications/V7/games/wump.c b/Applications/V7/games/wump.c
new file mode 100644 (file)
index 0000000..8ab384f
--- /dev/null
@@ -0,0 +1,381 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+/*
+ *     wumpus
+ *     stolen from PCC Vol 2 No 1
+ */
+
+#define        NBAT    3
+#define        NROOM   20
+#define        NTUNN   3
+#define        NPIT    3
+
+struct room {
+       int tunn[NTUNN];
+       int flag;
+} room[NROOM];
+
+char *intro[] = {
+       "\n",
+       "Welcome to 'Hunt the Wumpus.'\n",
+       "\n",
+       "The Wumpus lives in a cave of %d rooms.\n",
+       "Each room has %d tunnels leading to other rooms.\n",
+       "\n",
+       "Hazards:\n",
+       "\n",
+       "Bottomless Pits - Some rooms have Bottomless Pits in them.\n",
+       "       If you go there, you fall into the pit and lose!\n",
+       "Super Bats - Some other rooms have super bats.\n",
+       "       If you go there, a bat will grab you and take you to\n",
+       "       somewhere else in the cave where you could\n",
+       "       fall into a pit or run into the . . .\n",
+       "\n",
+       "Wumpus:\n",
+       "\n",
+       "The Wumpus is not bothered by the hazards since\n",
+       "he has sucker feet and is too big for a bat to lift.\n",
+       "\n",
+       "Usually he is asleep.\n",
+       "Two things wake him up:\n",
+       "       your entering his room\n",
+       "       your shooting an arrow anywhere in the cave.\n",
+       "If the wumpus wakes, he either decides to move one room or\n",
+       "stay where he was.  But if he ends up where you are,\n",
+       "he eats you up and you lose!\n",
+       "\n",
+       "You:\n",
+       "\n",
+       "Each turn you may either move or shoot a crooked arrow.\n",
+       "\n",
+       "Moving - You can move to one of the adjoining rooms;\n",
+       "       that is, to one that has a tunnel connecting it with\n",
+       "       the room you are in.\n",
+       "\n",
+       "Shooting - You have 5 arrows.  You lose when you run out.\n",
+       "       Each arrow can go from 1 to 5 rooms.\n",
+       "       You aim by telling the computer\n",
+       "       The arrow's path is a list of room numbers\n",
+       "       telling the arrow which room to go to next.\n",
+       "       The list is terminated with a 0.\n",
+       "       The first room in the path must be connected to the\n",
+       "       room you are in.  Each succeeding room must be\n",
+       "       connected to the previous room.\n",
+       "       If there is no tunnel between two of the rooms\n",
+       "       in the arrow's path, the arrow chooses one of the\n",
+       "       three tunnels from the room it's in and goes its\n",
+       "       own way.\n",
+       "\n",
+       "       If the arrow hits the wumpus, you win!\n",
+       "       If the arrow hits you, you lose!\n",
+       "\n",
+       "Warnings:\n",
+       "\n",
+       "When you are one or two rooms away from the wumpus,\n",
+       "the computer says:\n",
+       "               'I smell a Wumpus'\n",
+       "When you are one room away from some other hazard, it says:\n",
+       "               Bat    - 'Bats nearby'\n",
+       "               Pit    - 'I feel a draft'\n",
+       "\n",
+       0,
+};
+
+#define        BAT     01
+#define        PIT     02
+#define        WUMP    04
+
+int arrow;
+int loc;
+int wloc;
+int tchar;
+
+char rline(void)
+{
+       register char c, r;
+
+       while ((c = getchar()) == ' ');
+       r = c;
+       while (c != '\n' && c != ' ') {
+               if (c == '\0')
+                       exit(0);
+               c = getchar();
+       }
+       tchar = c;
+       return (r);
+}
+
+int rnum(int n)
+{
+       time_t t;
+       static int16_t first[2];
+
+       if (first[1] == 0) {
+               time(&t);
+               first[0] = (int) t;
+               first[1] = ((uint32_t) t) >> 16;
+               srand((first[1] * first[0]) ^ first[1]);
+       }
+       return ((rand() / 32768.0) * n);
+}
+
+int rin(void)
+{
+       register n, c;
+
+       n = 0;
+       c = getchar();
+       while (c != '\n' && c != ' ') {
+               if (c < '0' || c > '9') {
+                       while (c != '\n') {
+                               if (c == 0)
+                                       exit(0);
+                               c = getchar();
+                       }
+                       return (0);
+               }
+               n = n * 10 + c - '0';
+               c = getchar();
+       }
+       return (n);
+}
+
+int near(struct room *ap, int ahaz)
+{
+       register struct room *p;
+       register haz, i;
+
+       p = ap;
+       haz = ahaz;
+       for (i = 0; i < NTUNN; i++)
+               if (room[p->tunn[i]].flag & haz)
+                       return (1);
+       return (0);
+}
+
+int icomp(const void *v1, const void *v2)
+{
+       const int *p1 = v1;
+       const int *p2 = v2;
+
+       return (*p1 - *p2);
+}
+
+int tunnel(int i)
+{
+       register struct room *p;
+       register n, j;
+       int c;
+
+       c = 20;
+
+      loop:
+       n = rnum(NROOM);
+       if (n == i)
+               if (--c > 0)
+                       goto loop;
+       p = &room[n];
+       for (j = 0; j < NTUNN; j++)
+               if (p->tunn[j] == -1) {
+                       p->tunn[j] = i;
+                       return (n);
+               }
+       goto loop;
+}
+
+
+int main(int argc, char *argv[])
+{
+       register int i, j;
+       register struct room *p;
+       int k;
+
+       printf("Instructions? (y-n) ");
+       if (rline() == 'y')
+               for (i = 0; intro[i]; i++)
+                       printf(intro[i], i & 1 ? NROOM : NTUNN);
+
+
+/*
+ * initialize the room connections
+ */
+
+      init:
+       p = &room[0];
+       for (i = 0; i < NROOM; i++) {
+               for (j = 0; j < NTUNN; j++)
+                       p->tunn[j] = -1;
+               p++;
+       }
+       k = 0;
+       for (i = 1; i < NROOM;) {
+               j = rnum(NROOM);
+               p = &room[j];
+               if (j == k || p->tunn[0] >= 0 || p->tunn[1] >= 0)
+                       continue;
+               p->tunn[1] = k;
+               room[k].tunn[0] = j;
+               k = j;
+               i++;
+       }
+       p = &room[0];
+       for (i = 0; i < NROOM; i++) {
+               for (j = 0; j < NTUNN; j++) {
+                       if (p->tunn[j] < 0)
+                               p->tunn[j] = tunnel(i);
+                       if (p->tunn[j] == i)
+                               goto init;
+                       for (k = 0; k < j; k++)
+                               if (p->tunn[j] == p->tunn[k])
+                                       goto init;
+               }
+               qsort(&p->tunn[0], NTUNN, 2, icomp);
+               p++;
+       }
+
+/*
+ * put in player, wumpus,
+ * pits and bats
+ */
+
+      setup:
+       arrow = 5;
+       p = &room[0];
+       for (i = 0; i < NROOM; i++) {
+               p->flag = 0;
+               p++;
+       }
+       for (i = 0; i < NPIT;) {
+               p = &room[rnum(NROOM)];
+               if ((p->flag & PIT) == 0) {
+                       p->flag |= PIT;
+                       i++;
+               }
+       }
+       for (i = 0; i < NBAT;) {
+               p = &room[rnum(NROOM)];
+               if ((p->flag & (PIT | BAT)) == 0) {
+                       p->flag |= BAT;
+                       i++;
+               }
+       }
+       i = rnum(NROOM);
+       wloc = i;
+       room[i].flag |= WUMP;
+       for (;;) {
+               i = rnum(NROOM);
+               if ((room[i].flag & (PIT | BAT | WUMP)) == 0) {
+                       loc = i;
+                       break;
+               }
+       }
+
+/*
+ *     main loop of the game
+ */
+
+      loop:
+       printf("You are in room %d\n", loc + 1);
+       p = &room[loc];
+       if (p->flag & PIT) {
+               printf("You fell into a pit\n");
+               goto done;
+       }
+       if (p->flag & WUMP) {
+               printf("You were eaten by the wumpus\n");
+               goto done;
+       }
+       if (p->flag & BAT) {
+               printf("Theres a bat in your room\n");
+               loc = rnum(NROOM);
+               goto loop;
+       }
+       for (i = 0; i < NTUNN; i++)
+               if (near(&room[p->tunn[i]], WUMP))
+                       goto nearwump;
+       if (near(p, WUMP)) {
+             nearwump:
+               printf("I smell a wumpus\n");
+       }
+       if (near(p, BAT))
+               printf("Bats nearby\n");
+       if (near(p, PIT))
+               printf("I feel a draft\n");
+       printf("There are tunnels to");
+       for (i = 0; i < NTUNN; i++)
+               printf(" %d", p->tunn[i] + 1);
+       printf("\n");
+
+      again:
+       printf("Move or shoot (m-s) ");
+       switch (rline()) {
+       case 'm':
+               if (tchar == '\n')
+                       printf("which room? ");
+               i = rin() - 1;
+               for (j = 0; j < NTUNN; j++)
+                       if (i == p->tunn[j])
+                               goto groom;
+               printf("You hit the wall\n");
+               goto again;
+             groom:
+               loc = i;
+               if (i == wloc)
+                       goto mwump;
+               goto loop;
+
+       case 's':
+               if (tchar == '\n')
+                       printf("Give list of rooms terminated by 0\n");
+               for (i = 0; i < 5; i++) {
+                       j = rin() - 1;
+                       if (j == -1)
+                               break;
+                     ranarw:
+                       for (k = 0; k < NTUNN; k++)
+                               if (j == p->tunn[k])
+                                       goto garow;
+                       j = rnum(NROOM);
+                       goto ranarw;
+                     garow:
+                       p = &room[j];
+                       if (j == loc) {
+                               printf("You shot yourself\n");
+                               goto done;
+                       }
+                       if (p->flag & WUMP) {
+                               printf("You slew the wumpus\n");
+                               goto done;
+                       }
+               }
+               if (--arrow == 0) {
+                       printf("That was your last shot\n");
+                       goto done;
+               }
+               goto mwump;
+       }
+
+       goto again;
+
+      mwump:
+       p = &room[wloc];
+       p->flag &= ~WUMP;
+       i = rnum(NTUNN + 1);
+       if (i != NTUNN)
+               wloc = p->tunn[i];
+       room[wloc].flag |= WUMP;
+       goto loop;
+
+      done:
+       printf("Another game? (y-n) ");
+       if (rline() == 'y') {
+               printf("Same room setup? (y-n) ");
+               if (rline() == 'y')
+                       goto setup;
+               goto init;
+       }
+}