Bell 32V development
authorTom London <tbl@research.uucp>
Thu, 25 Jan 1979 07:04:59 +0000 (02:04 -0500)
committerTom London <tbl@research.uucp>
Thu, 25 Jan 1979 07:04:59 +0000 (02:04 -0500)
Work on file usr/src/cmd/learn/README
Work on file usr/src/cmd/learn/copy.c
Work on file usr/src/cmd/learn/dounit.c
Work on file usr/src/cmd/learn/lcount.c
Work on file usr/src/cmd/learn/learn.c
Work on file usr/src/cmd/learn/list.c
Work on file usr/src/cmd/learn/lrndef
Work on file usr/src/cmd/learn/lrnref
Work on file usr/src/cmd/learn/maktee.c
Work on file usr/src/cmd/learn/makpipe.c
Work on file usr/src/cmd/learn/mem.c
Work on file usr/src/cmd/learn/mysys.c
Work on file usr/src/cmd/learn/omakefile
Work on file usr/src/cmd/learn/origmakefile
Work on file usr/src/cmd/learn/selsub.c
Work on file usr/src/cmd/learn/selunit.c
Work on file usr/src/cmd/learn/start.c
Work on file usr/src/cmd/learn/tee.c
Work on file usr/src/cmd/learn/temp
Work on file usr/src/cmd/learn/whatnow.c
Work on file usr/src/cmd/learn/wrapup.c

Co-Authored-By: John Reiser <jfr@research.uucp>
Synthesized-from: 32v

21 files changed:
usr/src/cmd/learn/README [new file with mode: 0644]
usr/src/cmd/learn/copy.c [new file with mode: 0644]
usr/src/cmd/learn/dounit.c [new file with mode: 0644]
usr/src/cmd/learn/lcount.c [new file with mode: 0644]
usr/src/cmd/learn/learn.c [new file with mode: 0644]
usr/src/cmd/learn/list.c [new file with mode: 0644]
usr/src/cmd/learn/lrndef [new file with mode: 0644]
usr/src/cmd/learn/lrnref [new file with mode: 0644]
usr/src/cmd/learn/makpipe.c [new file with mode: 0644]
usr/src/cmd/learn/maktee.c [new file with mode: 0644]
usr/src/cmd/learn/mem.c [new file with mode: 0644]
usr/src/cmd/learn/mysys.c [new file with mode: 0644]
usr/src/cmd/learn/omakefile [new file with mode: 0644]
usr/src/cmd/learn/origmakefile [new file with mode: 0644]
usr/src/cmd/learn/selsub.c [new file with mode: 0644]
usr/src/cmd/learn/selunit.c [new file with mode: 0644]
usr/src/cmd/learn/start.c [new file with mode: 0644]
usr/src/cmd/learn/tee.c [new file with mode: 0644]
usr/src/cmd/learn/temp [new file with mode: 0644]
usr/src/cmd/learn/whatnow.c [new file with mode: 0644]
usr/src/cmd/learn/wrapup.c [new file with mode: 0644]

diff --git a/usr/src/cmd/learn/README b/usr/src/cmd/learn/README
new file mode 100644 (file)
index 0000000..1d5333e
--- /dev/null
@@ -0,0 +1,43 @@
+The C script is not complete; use at your own risk.
+
+Lessons are in
+       /usr/lib/learn/*
+Source is in
+       /usr/src/cmd/learn
+Miscellaneous supporting code is also in source.
+
+Make a learn by
+       make
+When this seems right, extract the lessons by
+       make lessons
+This extracts the lesson archives
+for each course.  You can also do this one step at a
+time with "make files", "make editor", etc.,
+if you don't want all courses.
+If you do things separately, you must also say
+       make play; make log
+
+Finally, check that it's sensible with
+       make check
+If that doesn't print any messages,
+you're probably in good shape.
+
+Learn requires general write permission on the user playpen
+directory .../lib/play.  Lesson directories may be protected.
+
+Learn collects a log file for each script in the .../lib/log
+directory, with a file for each script (files,
+editor, etc.) containing an entry for each lesson
+attempted. These files will grow without bound,
+unless they are periodically truncated. 
+The log files should have general write permission.
+If you don't want logging (a sensible position to take),
+set the variable "logging" to zero in source/lrndef
+before making learn.
+
+Learn requires about 1500 blocks to make itself,
+and about 1000 when completely made.
+
+Please report problems, bad lessons, etc., to
+Brian Kernighan, MH 6021, 2C-518, or
+Mike Lesk, MH 6377, 2C-572.  Thanks.
diff --git a/usr/src/cmd/learn/copy.c b/usr/src/cmd/learn/copy.c
new file mode 100644 (file)
index 0000000..8d1f0f7
--- /dev/null
@@ -0,0 +1,272 @@
+#include "stdio.h"
+#include "signal.h"
+#include "lrnref"
+
+char last[100];
+char logf[100];
+char subdir[100];
+extern char * ctime();
+
+copy(prompt, fin)
+FILE *fin;
+{
+       FILE *fout, *f;
+       char s[100], t[100], s1[100], *r, *tod;
+       char nm[30];
+       int *p, tv[2];
+       extern int intrpt(), *action();
+       extern char *wordb();
+       int nmatch = 0;
+
+       if (subdir[0]==0)
+               sprintf(subdir, "../../%s", sname);
+       for (;;) {
+               if (pgets(s, prompt, fin) == 0)
+                       if (fin == stdin) {
+                               /* fprintf(stderr, "Don't type control-D\n"); */
+                               /* this didn't work out very well */
+                               continue;
+                       } else
+                               break;
+               trim(s);
+               /* change the sequence %s to lesson directory */
+               /* if needed */
+               for (r = s; *r; r++)
+                       if (*r == '%') {
+                               sprintf(s1, s, subdir, subdir, subdir);
+                               strcpy(s, s1);
+                               break;
+                       }
+               r = wordb(s, t);
+               p = action(t);
+               if (*p == ONCE) {       /* some actions done only once per script */
+                       if (wrong) {    /* we are on 2nd time */
+                               scopy(fin, NULL);
+                               continue;
+                       }
+                       strcpy(s, r);
+                       r = wordb(s, t);
+                       p = action(t);
+               }
+               if (p == 0) {
+                       if (comfile >= 0) {
+                               write(comfile, s, strlen(s));
+                               write(comfile, "\n", 1);
+                       }
+                       else {
+                               signal(SIGINT, SIG_IGN);
+                               status = mysys(s);
+                               signal(SIGINT, intrpt);
+                       }
+                       if (incopy) {
+                               fprintf(incopy, "%s\n", s);
+                               strcpy(last, s);
+                       }
+                       continue;
+               }
+               switch (*p) {
+               case READY:
+                       if (incopy && r) {
+                               fprintf(incopy, "%s\n", r);
+                               strcpy(last, r);
+                       }
+                       return;
+               case PRINT:
+                       if (wrong)
+                               scopy(fin, NULL);       /* don't repeat message */
+                       else if (r)
+                               list(r);
+                       else
+                               scopy(fin, stdout);
+                       break;
+               case NOP:
+                       break;
+               case MATCH:
+                       if (nmatch > 0) /* we have already passed */
+                               scopy(fin, NULL);
+                       else if ((status = strcmp(r, last)) == 0) {     /* did we pass this time? */
+                               nmatch++;
+                               scopy(fin, stdout);
+                       } else
+                               scopy(fin, NULL);
+                       break;
+               case BAD:
+                       if (strcmp(r, last) == 0) {
+                               scopy(fin, stdout);
+                       } else
+                               scopy(fin, NULL);
+                       break;
+               case SUCCEED:
+                       scopy(fin, (status == 0) ? stdout : NULL);
+                       break;
+               case FAIL:
+                       scopy(fin, (status != 0) ? stdout : NULL);
+                       break;
+               case CREATE:
+                       fout = fopen(r, "w");
+                       scopy(fin, fout);
+                       fclose(fout);
+                       break;
+               case CMP:
+                       status = cmp(r);        /* contains two file names */
+                       break;
+               case MV:
+                       sprintf(nm, "%s/L%s.%s", subdir, todo, r);
+                       fcopy(r, nm);
+                       break;
+               case USER:
+               case NEXT:
+                       more = 1;
+                       return;
+               case COPYIN:
+                       incopy = fopen(".copy", "w");
+                       break;
+               case UNCOPIN:
+                       fclose(incopy);
+                       incopy = NULL;
+                       break;
+               case COPYOUT:
+                       maktee();
+                       break;
+               case UNCOPOUT:
+                       untee();
+                       break;
+               case PIPE:
+                       comfile = makpipe();
+                       break;
+               case UNPIPE:
+                       close(comfile);
+                       wait(0);
+                       comfile = -1;
+                       break;
+               case YES:
+               case NO:
+                       if (incopy) {
+                               fprintf(incopy, "%s\n", s);
+                               strcpy(last, s);
+                       }
+                       return;
+               case WHERE:
+                       printf("You are in lesson %s\n", todo);
+                       fflush(stdout);
+                       break;
+               case BYE:
+                       more=0;
+                       return;
+               case CHDIR:
+                       printf("cd not allowed\n");
+                       fflush(stdout);
+                       break;
+               case LEARN:
+                       printf("You are already in learn.\n");
+                       fflush(stdout);
+                       break;
+               case LOG:
+                       if (!logging)
+                               break;
+                       if (logf[0] == 0)
+                               sprintf(logf, "%s/log/%s", direct, sname);
+                       f = fopen( (r? r : logf), "a");
+                       if (f == NULL)
+                               break;
+                       time(tv);
+                       tod = ctime(tv);
+                       tod[24] = 0;
+                       fprintf(f, "%s L%-6s %s %2d %s\n", tod,
+                               todo, status? "fail" : "pass", speed, pwline);
+                       fclose(f);
+                       break;
+               }
+       }
+       return;
+}
+
+pgets(s, prompt, f)
+FILE *f;
+{
+       if (prompt) {
+               if (comfile < 0)
+                       printf("$ ");
+               fflush(stdout);
+       }
+       if (fgets(s, 100,f))
+               return(1);
+       else
+               return(0);
+}
+
+trim(s)
+char *s;
+{
+       while (*s)
+               s++;
+       if (*--s == '\n')
+               *s=0;
+}
+
+scopy(fi, fo)  /* copy fi to fo until a line with # */
+FILE *fi, *fo;
+{
+       int c;
+
+       while ((c = getc(fi)) != '#' && c != EOF) {
+               do {
+                       if (fo != NULL)
+                               putc(c, fo);
+                       if (c == '\n')
+                               break;
+               } while ((c = getc(fi)) != EOF);
+       }
+       if (c == '#')
+               ungetc(c, fi);
+       fflush(fo);
+}
+
+cmp(r) /* compare two files for status */
+char *r;
+{
+       char *s;
+       FILE *f1, *f2;
+       int c1, c2, stat;
+
+       for (s = r; *s != ' ' && *s != '\0'; s++)
+               ;
+       *s++ = 0;       /* r contains file 1 */
+       while (*s == ' ')
+               s++;
+       f1 = fopen(r, "r");
+       f2 = fopen(s, "r");
+       if (f1 == NULL || f2 == NULL)
+               return(1);      /* failure */
+       stat = 0;
+       for (;;) {
+               c1 = getc(f1);
+               c2 = getc(f2);
+               if (c1 != c2) {
+                       stat = 1;
+                       break;
+               }
+               if (c1 == EOF || c2 == EOF)
+                       break;
+       }
+       fclose(f1);
+       fclose(f2);
+       return(stat);
+}
+
+char *
+wordb(s, t)    /* in s, t is prefix; return tail */
+char *s, *t;
+{
+       int c;
+
+       while (c = *s++) {
+               if (c == ' ' || c == '\t')
+                       break;
+               *t++ = c;
+       }
+       *t = 0;
+       while (*s == ' ' || *s == '\t')
+               s++;
+       return(c ? s : NULL);
+}
diff --git a/usr/src/cmd/learn/dounit.c b/usr/src/cmd/learn/dounit.c
new file mode 100644 (file)
index 0000000..26a65d4
--- /dev/null
@@ -0,0 +1,59 @@
+#include "stdio.h"
+#include "lrnref"
+
+dounit()
+{
+       char tbuff[100];
+
+       if (todo == 0)
+               return;
+       wrong = 0;
+retry:
+       start(todo);
+       sprintf(tbuff, "../../%s/L%s", sname, todo);    /* script = lesson */
+       scrin = fopen(tbuff, "r");
+       if (scrin == NULL) {
+               fprintf(stderr, "No script.\n");
+               wrapup(1);
+       }
+
+       copy(0, scrin);
+       if (more == 0)
+               return;
+       copy(1, stdin);
+       if (more == 0)
+               return;
+       copy(0, scrin);
+
+       if (comfile >= 0)
+               close(comfile);
+       wait(&didok);
+       didok = (status == 0);
+       if (!didok) {
+               wrong++;
+               printf("\nSorry, that's %snot right.  Do you want to try again?  ",
+                       wrong > 1 ? "still " : "");
+               fflush(stdout);
+               for(;;) {
+                       gets(tbuff);
+                       if (tbuff[0] == 'y') {
+                               printf("Try the problem again.\n");
+                               fflush(stdout);
+                               goto retry;
+                       } else if (strcmp(tbuff, "bye") == 0) {
+                               wrapup(1);
+                       } else if (tbuff[0] == 'n') {
+                               wrong = 0;
+                               printf("\nOK.  Lesson %s (%d)\n", todo, speed);
+                               printf("Skipping to next lesson.\n\n");
+                               fflush(stdout);
+                               break;
+                       } else {
+                               printf("Please type yes, no or bye:  ");
+                               fflush(stdout);
+                       }
+               }
+       }
+       setdid(todo, sequence++);
+}
+
diff --git a/usr/src/cmd/learn/lcount.c b/usr/src/cmd/learn/lcount.c
new file mode 100644 (file)
index 0000000..110d827
--- /dev/null
@@ -0,0 +1,12 @@
+#include "stdio.h"
+
+main() /* count lines in something */
+{
+       register n, c;
+
+       n = 0;
+       while ((c = getchar()) != EOF)
+               if (c == '\n')
+                       n++;
+       printf("%d\n", n);
+}
diff --git a/usr/src/cmd/learn/learn.c b/usr/src/cmd/learn/learn.c
new file mode 100644 (file)
index 0000000..3080f3f
--- /dev/null
@@ -0,0 +1,47 @@
+#include "stdio.h"
+#include "lrndef"
+#include "lrnref"
+#include "signal.h"
+
+main(argc,argv)
+char *argv[];
+{
+       extern hangup(), intrpt();
+       extern char * getlogin();
+       char *malloc();
+
+       speed = 0;
+       more = 1;
+       pwline = getlogin();
+       setbuf(stdout, malloc(BUFSIZ));
+       selsub(argc, argv);
+       signal(SIGHUP, hangup);
+       signal(SIGINT, intrpt);
+       while (more) {
+               selunit();
+               dounit();
+               whatnow();
+       }
+       wrapup(0);
+}
+
+hangup()
+{
+       wrapup(1);
+}
+
+intrpt()
+{
+       char response[20], *p;
+
+       signal(SIGINT, hangup);
+       write(2, "\nInterrupt.\nWant to go on?  ", 28);
+       p = response;
+       *p = 'n';
+       while (read(0, p, 1) == 1 && *p != '\n')
+               p++;
+       if (response[0] != 'y')
+               wrapup(1);
+       ungetc('\n', stdin);
+       signal(SIGINT, intrpt);
+}
diff --git a/usr/src/cmd/learn/list.c b/usr/src/cmd/learn/list.c
new file mode 100644 (file)
index 0000000..76cf6e8
--- /dev/null
@@ -0,0 +1,30 @@
+#include "stdio.h"
+#include "lrnref"
+#include "signal.h"
+
+int istop;
+
+list(r)
+char *r;
+{
+       int stop(), intrpt();
+       FILE *ft;
+       char s[100];
+
+       if (r==0)
+               return;
+       istop = 1;
+       signal(SIGINT, stop);
+       ft = fopen(r, "r");
+       if (ft != NULL) {
+               while (fgets(s, 100, ft) && istop)
+                       fputs(s, stdout);
+               fclose(ft);
+       }
+       signal(SIGINT, intrpt);
+}
+
+stop()
+{
+       istop=0;
+}
diff --git a/usr/src/cmd/learn/lrndef b/usr/src/cmd/learn/lrndef
new file mode 100644 (file)
index 0000000..be6b992
--- /dev/null
@@ -0,0 +1,18 @@
+#include       <stdio.h>
+char   *direct = "/usr/lib/learn";     /* CHANGE THIS ON YOUR SYSTEM */
+int    more;
+char   *level;
+int    speed;
+char   *sname;
+char   *todo;
+FILE   *incopy = NULL;
+int    didok;
+int    sequence        = 1;
+int    comfile = -1;
+int    status;
+int    wrong;
+char   *pwline;
+char   *dir;
+FILE   *scrin;
+int    logging = 1;    /* set to 0 to turn off logging */
+int    ask;
diff --git a/usr/src/cmd/learn/lrnref b/usr/src/cmd/learn/lrnref
new file mode 100644 (file)
index 0000000..602c0b2
--- /dev/null
@@ -0,0 +1,46 @@
+#define        READY   0
+#define        PRINT   1
+#define        COPYIN  2
+#define        COPYOUT 3
+#define        UNCOPIN 4
+#define        UNCOPOUT        5
+#define        PIPE    6
+#define        UNPIPE  7
+#define        YES     8
+#define        NO      9
+#define        SUCCEED 10
+#define        FAIL    11
+#define        BYE     12
+#define        LOG     13
+#define        CHDIR   14
+#define        LEARN   15
+#define        MV      16
+#define        USER    17
+#define        NEXT    18
+#define        SKIP    19
+#define        WHERE   20
+#define        MATCH   21
+#define        NOP     22
+#define        BAD     23
+#define        CREATE  24
+#define        CMP     25
+#define        GOTO    26
+#define        ONCE    27
+
+extern int     more;
+extern char    *level;
+extern int     speed;
+extern char    *sname;
+extern char    *direct;
+extern char    *todo;
+extern int     didok;
+extern int     sequence;
+extern int     comfile;
+extern int     status;
+extern int     wrong;
+extern char    *pwline;
+extern char    *dir;
+extern FILE    *incopy;
+extern FILE    *scrin;
+extern int     logging;
+extern int     ask;
diff --git a/usr/src/cmd/learn/makpipe.c b/usr/src/cmd/learn/makpipe.c
new file mode 100644 (file)
index 0000000..94e09c8
--- /dev/null
@@ -0,0 +1,20 @@
+#include "stdio.h"
+
+makpipe()
+{
+       int f[2];
+
+       pipe(f);
+       if (fork()==0) {
+               close(f[1]);
+               close(0);
+               dup(f[0]);
+               close(f[0]);
+               execl ("/bin/sh", "sh", "-i", 0);
+               execl ("/usr/bin/sh", "sh", "-i", 0);
+               write(2,"Exec error\n",11);
+       }
+       close(f[0]);
+       sleep(2);       /* so shell won't eat up too much input */
+       return(f[1]);
+}
diff --git a/usr/src/cmd/learn/maktee.c b/usr/src/cmd/learn/maktee.c
new file mode 100644 (file)
index 0000000..1585ac2
--- /dev/null
@@ -0,0 +1,46 @@
+#include "stdio.h"
+#include "signal.h"
+#include "lrnref"
+
+static int oldout;
+static char tee[50];
+
+maktee()
+{
+       int fpip[2], in, out;
+
+       if (tee[0] == 0)
+               sprintf(tee, "%s/tee", direct);
+       pipe(fpip);
+       in = fpip[0];
+       out= fpip[1];
+       if (fork() == 0) {
+               signal(SIGINT, SIG_IGN);
+               close(0);
+               close(out);
+               dup(in);
+               close(in);
+               execl (tee, "lrntee", 0);
+               fprintf(stderr, "Tee exec failed\n");
+               exit(1);
+       }
+       close(in);
+       fflush(stdout);
+       oldout = dup(1);
+       close(1);
+       if (dup(out) != 1)
+               fprintf(stderr, "Error making tee for copyout\n");
+       close(out);
+       return(1);
+}
+
+untee()
+{
+       int x;
+
+       fflush(stdout);
+       close(1);
+       dup(oldout);
+       close(oldout);
+       wait(&x);
+}
diff --git a/usr/src/cmd/learn/mem.c b/usr/src/cmd/learn/mem.c
new file mode 100644 (file)
index 0000000..b226a8d
--- /dev/null
@@ -0,0 +1,94 @@
+# include "stdio.h"
+# include "lrnref"
+# define SAME 0
+
+struct keys {
+       char *k_wd;
+       int k_val;
+} keybuff[] = {
+       {"ready",       READY},
+       {"answer",      READY},
+       {"#print",      PRINT},
+       {"#copyin",     COPYIN},
+       {"#uncopyin",   UNCOPIN},
+       {"#copyout",    COPYOUT},
+       {"#uncopyout",  UNCOPOUT},
+       {"#pipe",       PIPE},
+       {"#unpipe",     UNPIPE},
+       {"#succeed",    SUCCEED},
+       {"#fail",       FAIL},
+       {"bye",         BYE},
+       {"chdir",       CHDIR},
+       {"cd",          CHDIR},
+       {"learn",       LEARN},
+       {"#log",        LOG},
+       {"yes",         YES},
+       {"no",          NO},
+       {"#mv",         MV},
+       {"#user",       USER},
+       {"#next",       NEXT},
+       {"skip",        SKIP},
+       {"#where",      WHERE},
+       {"#match",      MATCH},
+       {"#bad",        BAD},
+       {"#create",     CREATE},
+       {"#cmp",        CMP},
+       {"#goto",       GOTO},
+       {"#once",       ONCE},
+       {"#",           NOP},
+       {NULL,          0}
+};
+
+int *action(s)
+char *s;
+{
+       struct keys *kp;
+       for (kp=keybuff; kp->k_wd; kp++)
+               if (strcmp(kp->k_wd, s) == SAME)
+                       return(&(kp->k_val));
+       return(NULL);
+}
+
+# define NW 100
+# define NWCH 800
+struct whichdid {
+       char *w_less;
+       int w_seq;
+} which[NW];
+int nwh = 0;
+char whbuff[NWCH];
+char *whcp = whbuff;
+
+setdid(lesson, sequence)
+char *lesson;
+{
+       struct whichdid *pw;
+       for(pw=which; pw < which+nwh; pw++)
+               if (strcmp(pw->w_less, lesson) == SAME)
+                       {
+                       pw->w_seq = sequence;
+                       return;
+                       }
+       pw=which+nwh++;
+       if (nwh >= NW) {
+               fprintf(stderr, "nwh>=NW\n");
+               wrapup(1);
+       }
+       pw->w_seq = sequence;
+       pw->w_less = whcp;
+       while (*whcp++ = *lesson++);
+       if (whcp >= whbuff + NWCH) {
+               fprintf(stderr, "lesson name too long\n");
+               wrapup(1);
+       }
+}
+
+already(lesson, sequence)
+char *lesson;
+{
+       struct whichdid *pw;
+       for (pw=which; pw < which+nwh; pw++)
+               if (strcmp(pw->w_less, lesson) == SAME)
+                       return(1);
+       return(0);
+}
diff --git a/usr/src/cmd/learn/mysys.c b/usr/src/cmd/learn/mysys.c
new file mode 100644 (file)
index 0000000..77b4a2e
--- /dev/null
@@ -0,0 +1,120 @@
+#include "stdio.h"
+#include "signal.h"
+
+#define        EASY    1
+#define        MEDIUM  2
+#define        HARD    3
+
+mysys(s)
+char *s;
+{
+       /* like "system" but rips off "mv", etc.*/
+       /* also tries to guess if can get away with exec cmd */
+       /* instead of sh cmd */
+       char p[300];
+       char *np[40];
+       register char *t;
+       int nv, type, stat;
+
+       type = EASY;    /* we hope */
+       for (t = s; *t && type != HARD; t++) {
+               switch (*t) {
+               case '*': 
+               case '[': 
+               case '?': 
+               case '>': 
+               case '<': 
+               case '$':
+               case '\'':
+               case '"':
+                       type = MEDIUM;
+                       break;
+               case '|': 
+               case ';': 
+               case '&':
+                       type = HARD;
+                       break;
+               }
+       }
+       switch (type) {
+       case HARD:
+               return(system(s));
+       case MEDIUM:
+               strcpy(p, "exec ");
+               strcat(p, s);
+               return(system(p));
+       case EASY:
+               strcpy(p,s);
+               nv = getargs(p, np);
+               t=np[0];
+               if ((strcmp(t, "mv") == 0)||
+                   (strcmp(t, "cp") == 0)||
+                   (strcmp(t, "rm") == 0)||
+                   (strcmp(t, "ls") == 0) ) {
+                       if (fork() == 0) {
+                               char b[100];
+                               signal(SIGINT, SIG_DFL);
+                               strcpy(b, "/bin/");
+                               strcat(b, t);
+                               np[nv] = 0;
+                               execv(b, np);
+                               fprintf(stderr, "Execv failed\n");
+                               exit(1);
+                       }
+                       wait(&stat);
+                       return(stat);
+               }
+               return(system(s));
+       }
+}
+
+/*
+ * system():
+ *     same as library version, except that resets
+ *     default handling of signals in child, so that
+ *     user gets the behavior he expects.
+ */
+
+system(s)
+char *s;
+{
+       int status, pid, w;
+       register int (*istat)(), (*qstat)();
+
+       istat = signal(SIGINT, SIG_IGN);
+       qstat = signal(SIGQUIT, SIG_IGN);
+       if ((pid = fork()) == 0) {
+               signal(SIGINT, SIG_DFL);
+               signal(SIGQUIT, SIG_DFL);
+               execl("/bin/sh", "sh", "-c", s, 0);
+               _exit(127);
+       }
+       while ((w = wait(&status)) != pid && w != -1)
+               ;
+       if (w == -1)
+               status = -1;
+       signal(SIGINT, istat);
+       signal(SIGQUIT, qstat);
+       return(status);
+}
+
+getargs(s, v)
+char *s, **v;
+{
+       int i;
+
+       i = 0;
+       for (;;) {
+               v[i++]=s;
+               while (*s != 0 && *s!=' '&& *s != '\t')
+                       s++;
+               if (*s == 0)
+                       break;
+               *s++ =0;
+               while (*s == ' ' || *s == '\t')
+                       s++;
+               if (*s == 0)
+                       break;
+       }
+       return(i);
+}
diff --git a/usr/src/cmd/learn/omakefile b/usr/src/cmd/learn/omakefile
new file mode 100644 (file)
index 0000000..4ea6d42
--- /dev/null
@@ -0,0 +1,69 @@
+LESSONS = files editor morefiles macros eqn C
+
+FILES = lrndef lrnref \
+       copy.c dounit.c learn.c list.c \
+       makpipe.c maktee.c mem.c mysys.c selsub.c selunit.c \
+       start.c whatnow.c wrapup.c \
+       lcount.c tee.c \
+       makefile
+
+OBJECTS = copy.o dounit.o learn.o list.o mem.o \
+       makpipe.o maktee.o mysys.o selsub.o selunit.o \
+       start.o whatnow.o wrapup.o
+
+CFLAGS = -O
+LIBRARY =
+LLIB   = /usr/lib/learn
+
+cp:    all
+       cp learn /bin
+       cp tee $(LLIB)
+       cp lcount $(LLIB)
+       rm learn tee lcount *.o
+       @echo "Now do 'make lessons' if you need to extract the lesson archives"
+
+cmp:   all
+       cmp learn /bin/learn
+       cmp tee $(LLIB)/tee
+       cmp lcount $(LLIB)/lcount
+       rm learn tee lcount *.o
+
+all:   learn tee lcount
+
+learn: $(OBJECTS)
+       cc -n -s -o learn $(CFLAGS) $(OBJECTS) $(LIBRARY)
+
+$(OBJECTS): lrnref
+learn.o: lrndef
+
+tee:
+       cc $(CFLAGS) -s -n tee.c -o tee $(LIBRARY)
+
+lcount:
+       cc $(CFLAGS) -s -n lcount.c -o lcount $(LIBRARY)
+
+lessons:       $(LESSONS)
+
+files:
+       -if test ! -r $(LLIB)/files; then mkdir $(LLIB)/files; fi
+       (cd $(LLIB)/files; ar x ../files.a)
+
+morefiles:
+       -if test ! -r $(LLIB)/morefiles; then mkdir $(LLIB)/morefiles; fi
+       (cd $(LLIB)/morefiles; ar x ../morefiles.a)
+
+editor:
+       -if test ! -r $(LLIB)/editor; then mkdir $(LLIB)/editor; fi
+       (cd $(LLIB)/editor; ar x ../editor.a)
+
+macros:
+       -if test ! -r $(LLIB)/macros; then mkdir $(LLIB)/macros; fi
+       (cd $(LLIB)/macros; ar x ../macros.a)
+
+eqn:
+       -if test ! -r $(LLIB)/eqn; then mkdir $(LLIB)/eqn; fi
+       (cd $(LLIB)/eqn; ar x ../eqn.a)
+
+C:
+       -if test ! -r $(LLIB)/C; then mkdir $(LLIB)/C; fi
+       (cd $(LLIB)/C; ar x ../C.a)
diff --git a/usr/src/cmd/learn/origmakefile b/usr/src/cmd/learn/origmakefile
new file mode 100644 (file)
index 0000000..e7aa1f1
--- /dev/null
@@ -0,0 +1,68 @@
+LESSONS = files editor morefiles macros eqn C
+
+FILES = lrndef lrnref \
+       copy.c dounit.c learn.c list.c \
+       makpipe.c maktee.c mem.c mysys.c selsub.c selunit.c \
+       start.c whatnow.c wrapup.c \
+       lcount.c tee.c \
+       makefile ../README
+
+OBJECTS = copy.o dounit.o learn.o list.o mem.o \
+       makpipe.o maktee.o mysys.o selsub.o selunit.o \
+       start.o whatnow.o wrapup.o
+
+CFLAGS = -O
+LIBRARY = -lS
+
+a.out: $(OBJECTS)
+       cc -n $(CFLAGS) $(OBJECTS) $(LIBRARY)
+
+$(OBJECTS): lrnref
+learn.o: lrndef
+
+list:
+       pr $(FILES)
+
+bin:
+       cp a.out /usr/bin/learn
+       strip /usr/bin/learn
+
+lcount tee:
+       cc $(CFLAGS) -s $@.c -o ../lib/$@ $(LIBRARY)
+
+lessons:       $(LESSONS)
+
+play log:
+       -rm -r ../lib/$@; mkdir ../lib/$@; chmod +w ../lib/$@
+
+$(LESSONS):
+       -rm -r ../lib/$@
+       mkdir ../lib/$@
+       (cd ../lib/$@; ar x ../$@.a)
+
+everything:    a.out bin tee lcount lessons play log check
+
+archives:
+       (cd ../lib/files; ar r ../files.a L*)
+       (cd ../lib/morefiles; ar r ../morefiles.a L*)
+       (cd ../lib/editor; ar r ../editor.a L*)
+       (cd ../lib/macros; ar r ../macros.a L*)
+       (cd ../lib/eqn; ar r ../eqn.a L* tinyms Init)
+       (cd ../lib/C; ar r ../C.a L* get*)
+
+export:
+       : make the directories
+       mkdir export export/source export/lib
+       : copy source files
+       -cp $(FILES) export/source
+       : non-directories in lib
+       -for i in ../lib/*;\
+       do if test -f $$i; then cp $$i export/lib; fi;\
+       done
+
+check:
+       -@test -r ../lib/tee || echo 'tee not present; make tee'
+       -@test -r ../lib/lcount || echo 'lcount not present; make lcount'
+       -@test -r ../lib/play || echo 'play directory not present; make play'
+       -@test -r ../lib/log || echo 'log directory not present; make log'
+       -@for i in $(LESSONS); do test -r ../lib/$$i/L0 || echo $$i not unarchived, make $$i; done
diff --git a/usr/src/cmd/learn/selsub.c b/usr/src/cmd/learn/selsub.c
new file mode 100644 (file)
index 0000000..0685a5f
--- /dev/null
@@ -0,0 +1,94 @@
+#include "stdio.h"
+#include "lrnref"
+
+selsub(argc,argv)
+char *argv[];
+{
+       char ans1[100], *cp;
+       static char ans2[30];
+       static char dirname[20];
+       static char subname[20];
+
+       if (argc > 1 && argv[1][0] == '-') {
+               direct = argv[1]+1;
+               argc--;
+               argv++;
+       }
+       chknam(direct);
+       if (chdir(direct) != 0) {
+               fprintf(stderr, "can't cd to %s\,", direct);
+               exit(1);
+       }
+       sname = argc > 1 ? argv[1] : 0;
+       if (argc > 2)
+               strcpy (level=ans2, argv[2]);
+       else
+               level = 0;
+       if (argc > 3 )
+               speed = atoi(argv[3]);
+       if (!sname) {
+               printf("These are the available courses -\n");
+               list("Linfo");
+               printf("If you want more information about the courses,\n");
+               printf("or if you have never used 'learn' before,\n");
+               printf("type 'return'; otherwise type the name of\n");
+               printf("the course you want, followed by 'return'.\n");
+               fflush(stdout);
+               gets(sname=subname);
+               if (sname[0] == '\0') {
+                       list("Xinfo");
+                       do {
+                               printf("\nWhich subject?  ");
+                               fflush(stdout);
+                               gets(sname=subname);
+                       } while (sname[0] == '\0');
+               }
+       }
+       chknam(sname);
+       if (!level) {
+               printf("If you were in the middle of this subject\n");
+               printf("and want to start where you left off, type\n");
+               printf("the last lesson number the computer printed.\n");
+               printf("To start at the beginning, just hit return.\n");
+               fflush(stdout);
+               gets(ans2);
+               if (ans2[0]==0)
+                       strcpy(ans2,"0");
+               for (cp=ans2; *cp; cp++)
+                       if (*cp == '(' || *cp == ' ')
+                               *cp= 0;
+               level=ans2;
+       }
+
+       /* make new directory for user to play in */
+       if (chdir("play") != 0) {
+               fprintf(stderr, "can't cd to playpen\n");
+               exit(1);
+       }
+       sprintf(dir=dirname, "pl%da", getpid());
+       sprintf(ans1, "mkdir %s", dir);
+       system(ans1);
+       if (chdir(dir) < 0) {
+               fprintf(stderr, "Couldn't create working directory.\nBye.\n");
+               exit(1);
+       }
+       /* after this point, we have a working directory. */
+       /* have to call wrapup to clean up */
+       if (access(sprintf(ans1, "%s/%s/Init", direct, sname), 04)==0)
+               if (system(sprintf(ans1, "%s/%s/Init %s", direct,sname, level)) != 0) {
+                       printf("Leaving learn.\n");
+                       wrapup(1);
+               }
+       if (level[0] == '-')    /* no lesson names start with - */
+               ask = 1;
+       start(level);
+}
+
+chknam(name)
+char *name;
+{
+       if (access(name, 05) < 0) {
+               printf("Sorry, there is no subject or lesson named %s.\nBye.\n", name);
+               exit(1);
+       }
+}
diff --git a/usr/src/cmd/learn/selunit.c b/usr/src/cmd/learn/selunit.c
new file mode 100644 (file)
index 0000000..ed5d1c9
--- /dev/null
@@ -0,0 +1,102 @@
+#include "stdio.h"
+#include "lrnref"
+
+int    nsave   = 0;
+
+selunit()
+{
+       char fnam[20], s[50];
+       static char dobuff[50];
+       char posslev[20][20];
+       int diff[20], i, k, m, n, best, alts;
+       FILE *f;
+       char zb[200];
+       static char saved[20];
+
+       while (ask) {
+               printf("What lesson? ");
+               fflush(stdout);
+               gets(dobuff);
+               if (strcmp(dobuff, "bye") == 0)
+                       wrapup(0);
+               level = todo = dobuff;
+               sprintf(s, "../../%s/L%s", sname, dobuff);
+               if (access(s, 04) == 0)
+                       return;
+               printf("no such lesson\n");
+       }
+       alts = 0;
+retry:
+       f=scrin;
+       if (f==NULL) {
+               sprintf(fnam, "../../%s/L%s", sname, level);
+               f = fopen(fnam, "r");
+               if (f==NULL) {
+                       fprintf(stderr, "No script for lesson %s.\n", level);
+                       wrapup(1);
+               }
+               while (fgets(zb, 200, f)) {
+                       trim(zb);
+                       if (strcmp(zb, "#next")==0)
+                               break;
+               }
+       }
+       if (feof(f)) {
+               printf("Congratulations; you have finished this sequence.\n");
+               fflush(stdout);
+               todo = 0;
+               return;
+       }
+       for(i=0; fgets(s, 50, f); i++) {
+               sscanf(s, "%s %d", posslev[i], &diff[i]);
+       }
+       best = -1;
+       /* cycle through lessons from random start */
+       /* first try the current place, failing that back up to
+            last place there are untried alternatives (but only one backup) */
+       n = grand()%i;
+       for(k=0; k<i; k++) {
+               m = (n+k)%i;
+               if (already(posslev[m],0)) continue;
+               if (best<0) best=m;
+               /* real alternatives */
+               alts++;
+               if (abs(diff[m]-speed) < abs(diff[best]-speed))
+                       best=m;
+       }
+       if (best < 0 && nsave) {
+               nsave--;
+               strcpy(level, saved);
+               goto retry;
+       }
+       if (best <0) {
+               /* lessons exhausted or missing */
+               printf("Sorry, there are no alternative lessons at this stage.\n");
+               printf("See someone for help.\n");
+               fflush(stdout);
+               todo = 0;
+               return;
+       }
+       strcpy (dobuff, posslev[best]);
+       if (alts>1) {
+               nsave=1;
+               strcpy (saved, level);
+       }
+       todo = dobuff;
+       fclose(f);
+}
+
+abs(x)
+{
+       return(x>=0? x: -x);
+}
+
+grand()
+{
+       static int garbage;
+       int a[2], b;
+
+       time(a);
+       b = a[1]+10*garbage++;
+       return(b&077777);
+}
diff --git a/usr/src/cmd/learn/start.c b/usr/src/cmd/learn/start.c
new file mode 100644 (file)
index 0000000..4c6d36b
--- /dev/null
@@ -0,0 +1,54 @@
+#include "stdio.h"
+#include "lrnref"
+#define        ND      64
+
+start(lesson)
+char *lesson;
+{
+       struct direct {
+               int inode; 
+               char name[14];
+       };
+       struct direct dv[ND], *dm, *dp;
+       int f, c, n;
+       char where [100];
+
+       f = open(".", 0);
+       n = read(f, dv, ND*sizeof(*dp));
+       n /= sizeof(*dp);
+       if (n==ND)
+               fprintf(stderr, "lesson too long\n");
+       dm = dv+n;
+       for(dp=dv; dp<dm; dp++)
+               if (dp->inode) {
+                       n = strlen(dp->name);
+                       if (dp->name[n-2] == '.' && dp->name[n-1] == 'c')
+                               continue;
+                       c = dp->name[0];
+                       if (c>='a' && c<= 'z')
+                               unlink(dp->name);
+               }
+       close(f);
+       if (ask)
+               return;
+       sprintf(where, "../../%s/L%s", sname, lesson);
+       if (access(where, 04)==0)       /* there is a file */
+               return;
+       fprintf(stderr, "No lesson %s\n",lesson);
+       wrapup(1);
+}
+
+fcopy(new,old)
+char *new, *old;
+{
+       char b[512];
+       int n, fn, fo;
+       fn = creat(new, 0666);
+       fo = open(old,0);
+       if (fo<0) return;
+       if (fn<0) return;
+       while ( (n=read(fo, b, 512)) > 0)
+               write(fn, b, n);
+       close(fn);
+       close(fo);
+}
diff --git a/usr/src/cmd/learn/tee.c b/usr/src/cmd/learn/tee.c
new file mode 100644 (file)
index 0000000..e75c497
--- /dev/null
@@ -0,0 +1,32 @@
+main()
+{
+       int f, c;
+
+       f = creat(".ocopy", 0666);
+       while (read(0, &c, 1) == 1) {
+               write (1, &c, 1);
+               put(c, f);
+       }
+       fl(f);
+       close(f);
+}
+
+static char ln[512];
+char *p = ln;
+put(c, f)
+{
+       *p++ = c;
+       if (c == '\n') {
+               fl(f);
+               p=ln;
+       }
+}
+fl(f)
+{
+       register char *s;
+
+       s = ln;
+       while (*s == '$' && *(s+1) == ' ')
+               s += 2;
+       write(f, s, p-s);
+}
diff --git a/usr/src/cmd/learn/temp b/usr/src/cmd/learn/temp
new file mode 100644 (file)
index 0000000..8fe50c0
--- /dev/null
@@ -0,0 +1,5 @@
+play:
+       -rm -r ../lib/play; mkdir ../lib/play; chmod +w ../lib/play
+
+log:
+       -rm -r ../lib/log; mkdir ../lib/log; chmod +w ../lib/log
diff --git a/usr/src/cmd/learn/whatnow.c b/usr/src/cmd/learn/whatnow.c
new file mode 100644 (file)
index 0000000..7a61164
--- /dev/null
@@ -0,0 +1,28 @@
+#include "stdio.h"
+#include "lrnref"
+
+whatnow()
+{
+       if (todo == 0) {
+               more=0;
+               return;
+       }
+       if (didok) {
+               strcpy(level,todo);
+               if (speed<=9) speed++;
+       }
+       else {
+               speed -= 4;
+               /* the 4 above means that 4 right, one wrong leave
+                   you with the same speed. */
+               if (speed <0) speed=0;
+       }
+       if (wrong) {
+               speed -= 2;
+               if (speed <0 ) speed = 0;
+       }
+       if (didok && more) {
+               printf("\nGood.  Lesson %s (%d)\n\n",level, speed);
+               fflush(stdout);
+       }
+}
diff --git a/usr/src/cmd/learn/wrapup.c b/usr/src/cmd/learn/wrapup.c
new file mode 100644 (file)
index 0000000..cdf44cc
--- /dev/null
@@ -0,0 +1,26 @@
+#include "signal.h"
+#include "stdio.h"
+#include "lrnref"
+
+wrapup(n)
+int n;
+{
+       /* this routine does not use 'system' because it wants
+        interrupts turned off */
+       int retval, pid, pidw;
+
+       signal(SIGINT, SIG_IGN);
+       chdir("..");
+       if ( (pid=fork()) ==0) {
+               signal(SIGHUP, SIG_IGN);
+               execl("/bin/rm", "rm", "-r", dir, 0);
+               execl("/usr/bin/rm", "rm", "-r", dir, 0);
+               fprintf(stderr, "Can't find 'rm' command.\n");
+               exit(0);
+       }
+       printf("Bye.\n"); /* not only does this reassure user but 
+                       it stalls for time while deleting directory */
+       fflush(stdout);
+       /* printf("Wantd %d got %d val %d\n",pid, pidw, retval); */
+       exit(n);
+}