diff options
author | Ian Darwin <ian@cvs.openbsd.org> | 1998-09-28 15:45:48 +0000 |
---|---|---|
committer | Ian Darwin <ian@cvs.openbsd.org> | 1998-09-28 15:45:48 +0000 |
commit | 0436a5b6c19a613da918536b89a49cbcb38a2e4e (patch) | |
tree | a67948a0b07dbb07c82a2f45e028b99f0e42356a | |
parent | 85f240539c462832ad5363a277a61928b0d90a2a (diff) |
import BTL learn(1)
-rw-r--r-- | usr.bin/learn/README | 13 | ||||
-rw-r--r-- | usr.bin/learn/lib/Linfo | 6 | ||||
-rw-r--r-- | usr.bin/learn/lib/Xinfo | 19 | ||||
-rw-r--r-- | usr.bin/learn/src/Makefile | 37 | ||||
-rw-r--r-- | usr.bin/learn/src/README | 33 | ||||
-rw-r--r-- | usr.bin/learn/src/lcount.c | 12 | ||||
-rw-r--r-- | usr.bin/learn/src/learn.c | 989 | ||||
-rw-r--r-- | usr.bin/learn/src/learn.h | 49 | ||||
-rw-r--r-- | usr.bin/learn/src/tee.c | 41 |
9 files changed, 1199 insertions, 0 deletions
diff --git a/usr.bin/learn/README b/usr.bin/learn/README new file mode 100644 index 00000000000..c5ff5282d02 --- /dev/null +++ b/usr.bin/learn/README @@ -0,0 +1,13 @@ +Learn was originally written by Mike Lesk with some contributions +from Brian Kernighan. The paper in this directory dates from the +second version of learn, around 1979. + +This version of learn has been resurrected from the original V7 +source and edited enough that the source compiles and the +lessons can be executed. We have made no attempt to update the +lessons, nor to fix some of the glaring problems with the code. +Think of it as a historical document, not a polished system. + +cd src +make +learn diff --git a/usr.bin/learn/lib/Linfo b/usr.bin/learn/lib/Linfo new file mode 100644 index 00000000000..b27813c92b4 --- /dev/null +++ b/usr.bin/learn/lib/Linfo @@ -0,0 +1,6 @@ + files + editor + morefiles + macros + eqn + C diff --git a/usr.bin/learn/lib/Xinfo b/usr.bin/learn/lib/Xinfo new file mode 100644 index 00000000000..8ff69f526ed --- /dev/null +++ b/usr.bin/learn/lib/Xinfo @@ -0,0 +1,19 @@ +files - basic file handling commands +editor - text editor; must know about files first. +morefiles - more on file manipulations and other useful stuff +macros - "-ms" macros for BTL memos & papers; must know editor +eqn - typing mathematics; must know editor +C - writing programs in the C language; must know editor + +This is probably the proper order, but after you +have the "files" course and know the basics of "editor", +try anything you like. + +You can always leave learn by typing "bye" (and a RETURN). +You can stop it from typing by pushing interrupt +(or break or rubout or delete, depending on your terminal). + +If it won't accept your answer, and you know____ you're +right, answer "no" when it asks whether you +want to try again, and it will go on to the next lesson. +Please report troubles to your local guru. diff --git a/usr.bin/learn/src/Makefile b/usr.bin/learn/src/Makefile new file mode 100644 index 00000000000..f03ab63fc7c --- /dev/null +++ b/usr.bin/learn/src/Makefile @@ -0,0 +1,37 @@ +LESSONS = files editor morefiles macros eqn C + +CFLAGS = -g +LLIB = ../lib + +cp: all + cp learn tee lcount $(LLIB) + @echo "Do 'make lessons' if you need to extract the lesson archives" + @echo "Do 'make play; make log' to make playpen and log directories" + +all: learn tee lcount + +learn: learn.c learn.h + cc -o learn $(CFLAGS) '-DLLIB="$(LLIB)"' learn.c + +lcount tee: + cc $(CFLAGS) $@.c -o $@ + +lessons: $(LESSONS) + +$(LESSONS): + -rm -rf $(LLIB)/$@ + mkdir $(LLIB)/$@ + (cd $(LLIB)/$@; ar x ../$@.a) + +play log: + -rm -rf $(LLIB)/$@; mkdir $(LLIB)/$@; chmod +w $(LLIB)/$@ + +check: + -@test -r $(LLIB)/tee || echo 'tee not present; make tee' + -@test -r $(LLIB)/lcount || echo 'lcount not present; make lcount' + -@test -r $(LLIB)/play || echo 'play directory not present; make play' + -@test -r $(LLIB)/log || echo 'log directory not present; make log' + -@for i in $(LESSONS); do test -r $(LLIB)/$$i/L0 || echo $$i not unarchived, make $$i; done + +clean: + rm -rf lcount learn tee $(LLIB)/play $(LLIB)/log diff --git a/usr.bin/learn/src/README b/usr.bin/learn/src/README new file mode 100644 index 00000000000..acf5ccc7a2a --- /dev/null +++ b/usr.bin/learn/src/README @@ -0,0 +1,33 @@ +This is a historical document describing code that once +worked fine. It sort of limps along now, but there are +some things that don't work right. Caveat emptor. + + +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. The C script is not +complete; use at your own risk. + +To set up the working directories, 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. diff --git a/usr.bin/learn/src/lcount.c b/usr.bin/learn/src/lcount.c new file mode 100644 index 00000000000..110d827bc9c --- /dev/null +++ b/usr.bin/learn/src/lcount.c @@ -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.bin/learn/src/learn.c b/usr.bin/learn/src/learn.c new file mode 100644 index 00000000000..4c5c521bd1d --- /dev/null +++ b/usr.bin/learn/src/learn.c @@ -0,0 +1,989 @@ +#include "stdio.h" +#include "learn.h" +#include "signal.h" +#include <stdlib.h> + +char *direct = LLIB; /* 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; + +main(int argc, char **argv) +{ + extern char * getlogin(); + + 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); +} + +void hangup(int x) +{ + wrapup(1); +} + +void intrpt(int x) +{ + 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); +} + + +char last[100]; +char logf[100]; +char subdir[200]; +extern char * ctime(); + +copy(prompt, fin) +FILE *fin; +{ + FILE *fout, *f; + char s[200], t[200], s1[200], *r, *tod; + char nm[100]; + int *p, tv[2]; + extern int *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 && *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(char *s, int prompt, 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); + if (fo != NULL) + 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); +} + + +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++); +} + +int istop; + +list(r) +char *r; +{ + void stop(int); + FILE *ft; + char s[200]; + + if (r==0) + return; + istop = 1; + signal(SIGINT, stop); + ft = fopen(r, "r"); + if (ft != NULL) { + while (fgets(s, sizeof s, ft) && istop) + fputs(s, stdout); + fclose(ft); + } + signal(SIGINT, intrpt); +} + +void stop(int x) +{ + istop=0; +} + +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]); +} + +static int oldout; +static char tee[100]; + +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); +} + +# 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); +} + + +#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. + */ + +int system(const char *s) +{ + int status, pid, w; + void (*istat)(void (*)(int)), (*qstat)(void (*)(int)); + + 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); +} + + +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\n", 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) { + sprintf(ans1, "%s/%s/Init %s", direct,sname, level); + if (system(ans1) != 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); + } +} + + +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); +} + +#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); +} + + +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); + } +} + + +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); +} diff --git a/usr.bin/learn/src/learn.h b/usr.bin/learn/src/learn.h new file mode 100644 index 00000000000..f597d9e2353 --- /dev/null +++ b/usr.bin/learn/src/learn.h @@ -0,0 +1,49 @@ +#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; + +extern void intrpt(int); +extern void hangup(int); diff --git a/usr.bin/learn/src/tee.c b/usr.bin/learn/src/tee.c new file mode 100644 index 00000000000..6d2a94b44c2 --- /dev/null +++ b/usr.bin/learn/src/tee.c @@ -0,0 +1,41 @@ +char *PS1; + +main() +{ + int f; + char c; + char *getenv(char *); + + PS1 = getenv("PS1"); + if (PS1==0) + PS1 = "$ "; + f = creat(".ocopy", 0666); + while (read(0, &c, 1) == 1) { + write (1, &c, 1); + put(c, f); + } + fl(f); + close(f); +} + +static char ln[5120]; +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; + if (strncmp(s, PS1, strlen(PS1)) == 0) + s += strlen(PS1); + write(f, s, p-s); +} |