xref: /original-bsd/usr.bin/learn/learn/copy.c (revision 262b24ac)
1 #ifndef lint
2 static char sccsid[] = "@(#)copy.c	4.4	(Berkeley)	09/11/87";
3 #endif not lint
4 
5 #include "stdio.h"
6 #include "signal.h"
7 #include "lrnref.h"
8 
9 char togo[50];
10 char last[100];
11 char logf[100];
12 char subdir[100];
13 extern char *ctime();
14 extern int review;
15 int noclobber;
16 
17 copy(prompt, fin)
18 int prompt;
19 FILE *fin;
20 {
21 	FILE *fout, *f;
22 	char s[100], t[100], s1[100], nm[30];
23 	char *r, *tod, c;
24 	int *p, tv[2];
25 	extern int intrpt(), *action();
26 	extern char *wordb();
27 	int nmatch = 0;
28 	long mark;
29 
30 	if (subdir[0]==0)
31 		sprintf(subdir, "%s/%s", direct, sname);
32 	for (;;) {
33 		if (pgets(s, prompt, fin) == 0)
34 			if (fin == stdin) {
35 				fprintf(stderr, "Type \"bye\" if you want to leave learn.\n");
36 				fflush(stderr);
37 				clearerr(stdin);
38 				continue;
39 			} else
40 				break;
41 		trim(s);		/* trim newline */
42 		/* change the sequence %s to lesson directory */
43 		/* if needed */
44 		for (r = s; *r; r++)
45 			if (*r == '%') {
46 				sprintf(s1, s, subdir, subdir, subdir);
47 				strcpy(s, s1);
48 				break;
49 			}
50 		r = wordb(s, t);	/* t = first token, r = rest */
51 		p = action(t);		/* p = token class */
52 		if (p && *p == ONCE) {	/* some actions done only once per script */
53 			if (wrong && !review) {	/* we are on 2nd time */
54 				scopy(fin, NULL);
55 				continue;
56 			}
57 			strcpy(s, r);
58 			r = wordb(s, t);
59 			p = action(t);
60 		}
61 		if (p == 0) {
62 			if (comfile >= 0) {	/* if #pipe in effect ... */
63 				write(comfile, s, strlen(s));
64 				write(comfile, "\n", 1);
65 			}
66 			else {		/* else must be UNIX command ... */
67 				signal(SIGINT, SIG_IGN);
68 				status = mysys(s);
69 				signal(SIGINT, intrpt);
70 			}
71 			if (incopy) {
72 				fprintf(incopy, "%s\n", s);
73 				strcpy(last, s);
74 			}
75 			continue;
76 		}
77 		switch (*p) {
78 		case READY:
79 			if (incopy && r) {
80 				fprintf(incopy, "%s\n", r);
81 				strcpy(last, r);
82 			}
83 			return;
84 		case PRINT:
85 			if (wrong)
86 				scopy(fin, NULL);	/* don't repeat message */
87 			else if (r)
88 				list(r);
89 			else
90 				scopy(fin, stdout);
91 			break;
92 		case HINT:
93 			mark = ftell(scrin);
94 			if (r)
95 				rewind(scrin);
96 			while ((int)(c=fgetc(scrin)) != EOF)
97 				putchar(c);
98 			fflush(stdout);
99 			fseek(scrin, mark, 0);
100 			break;
101 		case NOP:
102 			break;
103 		case MATCH:
104 			if (nmatch > 0)	/* we have already passed */
105 				scopy(fin, NULL);
106 			else if ((status = strcmp(r, last)) == 0) {	/* did we pass this time? */
107 				nmatch++;
108 				scopy(fin, stdout);
109 			} else
110 				scopy(fin, NULL);
111 			break;
112 		case BAD:
113 			if (strcmp(r, last) == 0) {
114 				scopy(fin, stdout);
115 			} else
116 				scopy(fin, NULL);
117 			break;
118 		case SUCCEED:
119 			scopy(fin, (status == 0) ? stdout : NULL);
120 			break;
121 		case FAIL:
122 			scopy(fin, (status != 0) ? stdout : NULL);
123 			break;
124 		case CREATE:
125 			if (noclobber)
126 				fout = NULL;
127 			else
128 				fout = fopen(r, "w");
129 			scopy(fin, fout);
130 			if (!noclobber)
131 				fclose(fout);
132 			break;
133 		case CMP:
134 			status = cmp(r);	/* contains two file names */
135 			break;
136 		case MV:
137 			sprintf(nm, "%s/L%s.%s", subdir, todo, r);
138 			fcopy(r, nm);
139 			break;
140 		case USER:
141 		case NEXT:
142 			if (noclobber)
143 				noclobber = 0;
144 			more = 1;
145 			return;
146 		/* "again previous_lesson" has a hard-to-reproduce bug */
147 		case AGAIN:
148 			review = 0;
149 			if (!r) {
150 				r = todo;
151 				noclobber = 1;
152 				review = 1;
153 			}
154 			again = 1;
155 			strcpy(togo, r);
156 			unhook();
157 			return;
158 		case SKIP:
159 			skip = 1;
160 			unhook();
161 			return;
162 		case COPYIN:
163 			incopy = fopen(".copy", "w");
164 			break;
165 		case UNCOPIN:
166 			fclose(incopy);
167 			incopy = NULL;
168 			break;
169 		case COPYOUT:
170 			teed = maktee();
171 			break;
172 		case UNCOPOUT:
173 			untee();
174 			teed = 0;
175 			break;
176 		case PIPE:
177 			comfile = makpipe();
178 			break;
179 		case UNPIPE:
180 			close(comfile);
181 			wait(0);
182 			comfile = -1;
183 			break;
184 		case YES:
185 		case NO:
186 			if (incopy) {
187 				fprintf(incopy, "%s\n", s);
188 				strcpy(last, s);
189 			}
190 			return;
191 		case WHERE:
192 			printf("You are in lesson %s of \"%s\" with a speed rating of %d.\n", todo, sname, speed);
193 			printf("You have completed %d out of a possible %d lessons.\n", sequence-1, total);
194 			if (r)
195 				tellwhich();
196 			fflush(stdout);
197 			break;
198 		case BYE:
199 			more=0;
200 			return;
201 		case CHDIR:
202 			printf("cd not allowed\n");
203 			fflush(stdout);
204 			break;
205 		case LEARN:
206 			printf("You are already in learn.\n");
207 			fflush(stdout);
208 			break;
209 		case LOG:	/* logfiles should be created mode 666 */
210 			if (!logging)
211 				break;
212 			if (logf[0] == 0)
213 				sprintf(logf, "%s/log/%s", direct, sname);
214 			f = fopen((r ? r : logf), "a");
215 			if (f == NULL)
216 				break;
217 			time(tv);
218 			tod = ctime(tv);
219 			tod[24] = 0;
220 			fprintf(f, "%s L%-6s %s %2d %s\n", tod,
221 				todo, status? "fail" : "pass", speed, pwline);
222 			fclose(f);
223 			break;
224 		}
225 	}
226 	return;
227 }
228 
229 pgets(s, prompt, f)
230 char *s;
231 int prompt;
232 FILE *f;
233 {
234 	if (prompt) {
235 		if (comfile < 0)
236 			fputs("% ", stdout);
237 		fflush(stdout);
238 	}
239 	if (fgets(s, 100,f))
240 		return(1);
241 	else
242 		return(0);
243 }
244 
245 trim(s)
246 char *s;
247 {
248 	while (*s)
249 		s++;
250 	if (*--s == '\n')
251 		*s=0;
252 }
253 
254 scopy(fi, fo)	/* copy fi to fo until a line with #
255 		 * sequence "#\n" means a line not ending with \n
256 		 * control-M's are filtered out */
257 FILE *fi, *fo;
258 {
259 	int c;
260 
261 	while ((c = getc(fi)) != '#' && c != EOF) {
262 		do {
263 			if (c == '#')   {
264 				c = getc(fi);
265 				if (c == '\n')
266 					break;
267 				if (c == EOF)   {
268 					if (fo != NULL)
269 						fflush(fo);
270 					return;
271 				}
272 				if (fo != NULL)
273 					putc('#', fo);
274 			}
275 			if (c == '\r')
276 				break;
277 			if (fo != NULL)
278 				putc(c, fo);
279 			if (c == '\n')
280 				break;
281 		} while ((c = getc(fi)) != EOF);
282 	}
283 	if (c == '#')
284 		ungetc(c, fi);
285 	if (fo != NULL)
286 		fflush(fo);
287 }
288 
289 cmp(r)	/* compare two files for status; #cmp f1 f2 [ firstnlinesonly ] */
290 char *r;
291 {
292 	char *s, *h;
293 	FILE *f1, *f2;
294 	int c1, c2, stat, n;
295 
296 	for (s = r; *s != ' ' && *s != '\0'; s++)
297 		;
298 	*s++ = 0;	/* r contains file 1 */
299 	while (*s == ' ')
300 		s++;
301 	for (h = s; *h != ' ' && *h != '\0'; h++)
302 		;
303 	if (*h) {
304 		*h++ = 0;
305 		while (*h == ' ')
306 			h++;
307 		n = atoi(h);
308 	}
309 	else
310 		n = 077777;
311 	f1 = fopen(r, "r");
312 	f2 = fopen(s, "r");
313 	if (f1 == NULL || f2 == NULL)
314 		return(1);	/* failure */
315 	stat = 0;
316 	for (;;) {
317 		c1 = getc(f1);
318 		c2 = getc(f2);
319 		if (c1 != c2) {
320 			stat = 1;
321 			break;
322 		}
323 		if (*h && c1 == '\n')
324 			if (--n)
325 				break;
326 		if (c1 == EOF || c2 == EOF)
327 			break;
328 	}
329 	fclose(f1);
330 	fclose(f2);
331 	return(stat);
332 }
333 
334 char *
335 wordb(s, t)	/* in s, t is prefix; return tail */
336 char *s, *t;
337 {
338 	int c;
339 
340 	while (c = *s++) {
341 		if (c == ' ' || c == '\t')
342 			break;
343 		*t++ = c;
344 	}
345 	*t = 0;
346 	while (*s == ' ' || *s == '\t')
347 		s++;
348 	return(c ? s : NULL);
349 }
350 
351 unhook()
352 {
353 	if (incopy) {
354 		fclose(incopy);
355 		incopy = NULL;
356 	}
357 	if (comfile >= 0) {
358 		close(comfile);
359 		wait(0);
360 		comfile = -1;
361 	}
362 	if (teed) {
363 		teed = 0;
364 		untee();
365 	}
366 	fclose(scrin);
367 	scrin = NULL;
368 }
369