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