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