|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2: static char rcsid[] = "$Header: comm.c,v 2.4 85/08/22 16:00:49 timo Exp $";
3:
4: /*
5: * B editor -- Communication with B interpreter.
6: */
7:
8: #include "feat.h"
9: #ifdef BTOP
10:
11: #include <signal.h>
12: #include <setjmp.h>
13: #include <ctype.h>
14:
15: #include "b.h"
16: #include "node.h"
17: #include "supr.h"
18: #include "unix.h"
19: #include "cell.h" /* For winheight */
20:
21: #define TABS 8
22:
23: string unixerror();
24:
25:
26: /*
27: * Communication to other modules (demo, getc, ...):
28: */
29:
30: Visible bool interrupted; /* Set when interrupt caught but not propagated */
31: Visible bool canjump; /* Set when disrupt() can safely longjmp(jumpback) */
32: Visible jmp_buf jumpback; /* Set by other module where to jump */
33:
34: /*
35: * Pipeline protocol with interpreter:
36: */
37:
38: #define ESCAPE '\001' /* Character signalling special function */
39: #define RESYNC '\177' /* Character signalling acknowledge of interrupt */
40: #define INTRCHILD SIGTRAP /* Signal to send as interrupt */
41:
42: #ifndef INTERPRETER
43: #define INTERPRETER "/usr/new/lib/B/bint"
44: #endif
45:
46: /*
47: * Local definitions:
48: */
49:
50: #ifndef INTRMSG
51: #define INTRMSG "*** Interrupted" /* Acknowledges interrupt */
52: #endif INTRMSG
53:
54: #define Moreinput(stream) ((stream)->_cnt > 0)
55:
56: Hidden int fdown[2]; /* File descriptors for pipe down */
57: Hidden int fup[2]; /* Pipe up */
58:
59: Hidden int pid; /* Process id of child */
60:
61: Hidden FILE *pdown; /* FILE pointer for pipe down to child process */
62: Hidden FILE *pup; /* Pipe up */
63:
64: Hidden string interpreter; /* Name of interpreter to be used */
65:
66:
67: Hidden char pushback[100]; /* Limited pushback facility */
68: Hidden int npushback; /* Number of characters pushed back */
69:
70:
71: /*
72: * Routine to set canjump, do a getc, and clear canjump.
73: */
74:
75: Visible int
76: ffgetc(fp)
77: FILE *fp;
78: {
79: register int c;
80:
81: canjump = Yes;
82: c = getc(fp);
83: canjump = No;
84: return c;
85: }
86:
87:
88: /*
89: * Similar for fgets.
90: */
91:
92: Visible string
93: ffgets(buf, len, fp)
94: string buf;
95: int len;
96: FILE *fp;
97: {
98: canjump = Yes;
99: buf = fgets(buf, len, fp);
100: canjump = No;
101: return buf;
102: }
103:
104:
105: /*
106: * Assign values to `fdown' and `fup'.
107: */
108:
109: Hidden Procedure
110: getdevices()
111: {
112: if (pipe(fdown) < 0 || pipe(fup) < 0)
113: syserr("%s", unixerror("can't pipe"));
114: }
115:
116:
117: /*
118: * Do the magic required for child-birth.
119: */
120:
121: Hidden Procedure
122: makechild()
123: {
124: #ifdef VFORK
125: pid = vfork();
126: #else VFORK
127: pid = fork();
128: #endif VFORK
129: if (pid == -1)
130: syserr("%s", unixerror("can't fork"));
131: if (pid == 0) /* Child */
132: exec_b(); /* Does not return */
133: /* Parent */
134: close(fdown[0]);
135: close(fup[1]);
136: }
137:
138:
139: /*
140: * Code executed in the child process. Never returns.
141: * Just dup the pipe ends to files 0, a and 2 (stdin, stdout and stderr),
142: * then close the original pipes.
143: */
144:
145: Hidden Procedure
146: exec_b()
147: {
148: close(fdown[1]), close(fup[0]);
149: close(0), close(1), close(2);
150: dup(fdown[0]), dup(fup[1]), dup(fup[1]);
151: close(fdown[0]), close(fup[1]);
152: execl(interpreter, interpreter, "-i", (char*)NULL);
153: fprintf(stderr, "*** ");
154: perror(interpreter);
155: _exit(1);
156: }
157:
158:
159: /*
160: * Interrupt handler.
161: * Usually only the flag `interrupted' is set.
162: *
163: * When `canjump' is on, it is cleared and we do a longjmp
164: * back to where jumpbuf leads us (usually done when a read
165: * system call is interrupted, as 4.2BSD tends to continue
166: * these rather than have them return with errno = EINTR).
167: */
168:
169: Hidden Procedure
170: disrupt()
171: {
172: interrupted = Yes;
173: signal(SIGINT, disrupt);
174: if (canjump) {
175: canjump = No;
176: longjmp(jumpback, 1);
177: }
178: }
179:
180:
181: /*
182: * Start the B interpreter as a subprocess.
183: * Set up communication pipes in pdown, pup.
184: */
185:
186: Visible Procedure
187: start_b(ppdown, ppup)
188: FILE **ppdown;
189: FILE **ppup;
190: {
191: interpreter = getenv("B_INTERPRETER");
192: if (!interpreter)
193: interpreter = INTERPRETER;
194: getdevices();
195: makechild();
196: pdown = fdopen(fdown[1], "w");
197: pup = fdopen(fup[0], "r");
198: if (!pdown || !pup)
199: syserr("%s", unixerror("can't fdopen"));
200: *ppdown = pdown;
201: *ppup = pup;
202: signal(SIGINT, disrupt);
203: }
204:
205:
206: /*
207: * Routine to be called after each line of data has been passed
208: * to the B interpreter; it checks whether the immediate next
209: * output is a request for an immediate command, and if so,
210: * eats the request and returns Yes. Otherwise it pushes back the
211: * request for later processing by sleur(), and returns No.
212: * ***** The prompt parameter is a relict of old times. *****
213: */
214:
215: Visible bool
216: expect(prompt)
217: string prompt; /* Only first char used; should be ">" */
218: {
219: register int c;
220:
221: fflush(pdown);
222: if (setjmp(jumpback))
223: return No;
224: if (npushback)
225: c = pushback[--npushback];
226: else
227: c = ffgetc(pup);
228: if (c != ESCAPE) {
229: if (c != EOF)
230: pushback[npushback++] = c;
231: return No;
232: }
233: if (npushback)
234: c = pushback[--npushback];
235: else
236: c = ffgetc(pup);
237: if (c == *prompt)
238: return Yes;
239: if (c != EOF)
240: pushback[npushback++] = c;
241: pushback[npushback++] = ESCAPE;
242: return No;
243: }
244:
245:
246: Visible int
247: sleur()
248: {
249: register int c;
250: register int x = 0;
251: bool show = Yes; /* No when looking for interrupt sync char */
252: bool idle = Yes; /* Yes when no output done yet this call */
253:
254: fflush(pdown);
255:
256: for (;;) {
257: if (interrupted) {
258: interrupted = No;
259: intrchild();
260: show = No;
261: }
262: if (show && npushback == 0 && !Moreinput(pup))
263: fflush(stdout);
264: if (setjmp(jumpback))
265: continue;
266: if (npushback > 0)
267: c = pushback[--npushback];
268: else
269: c = ffgetc(pup);
270: if (c == EOF) { /* End-of-file: B interpreter has terminated. */
271: fflush(stdout);
272: return EOF;
273: }
274: if (c == RESYNC) {
275: /* B interpreter acknowledges interrupt. */
276: if (!show) {
277: if (x != 0) putchar('\n');
278: fputs(INTRMSG, stdout);
279: putchar('\n');
280: x = 0;
281: show = Yes;
282: }
283: continue;
284: }
285: if (show) {
286: if (c != ESCAPE) {
287: putchar(c);
288: switch (c) {
289: case '\t':
290: x = (x/TABS + 1)*TABS;
291: break;
292: case '\b':
293: if (x > 0) --x;
294: break;
295: case '\r':
296: case '\n':
297: x = 0;
298: break;
299: default:
300: if (isascii(c) && isprint(c)
301: || c == ' ') ++x;
302: break;
303: }
304: }
305: else {
306: /* Control-A: B interpreter needs input. */
307: if (setjmp(jumpback))
308: continue;
309: if (npushback)
310: c = pushback[--npushback];
311: else {
312: c = ffgetc(pup);
313: if (c == EOF) {
314: return EOF;
315: }
316: }
317: if (c == '>') {
318: /* Newline before command prompt */
319: if (x != 0) putchar('\n');
320: x = 0;
321: }
322: setindent(x);
323: fflush(stdout);
324: return c;
325: }
326: }
327: }
328: }
329:
330:
331: /*
332: * Send the child a termination signal (SIGTERM).
333: */
334:
335: Visible Procedure
336: termchild()
337: {
338: if (pid) {
339: kill(pid, SIGTERM);
340: pid = 0;
341: }
342: }
343:
344:
345: /*
346: * Send the child an interrupt signal. (By convention, this is SIGTRAP).
347: */
348:
349: Visible Procedure
350: intrchild()
351: {
352: if (pid) {
353: kill(pid, INTRCHILD);
354: fflush(stdout);
355: }
356: }
357:
358:
359: /*
360: * Wait for child process and report abnormal exit statuses.
361: */
362:
363: Visible Procedure
364: waitchild()
365: {
366: int k;
367: int status;
368:
369: if (pid) {
370: while ((k = wait(&status)) != -1) {
371: if (k != pid)
372: #ifndef SMALLSYS
373: fprintf(stderr, "*** [Pid %d status 0%o]\n", pid, status)
374: #endif SMALLSYS
375: ;
376: else {
377: #ifndef SMALLSYS
378: if (status&0377)
379: fprintf(stderr, "*** Interpreter killed by signal %d%s\n",
380: status&0177, status&0200 ? " - core dumped" : "");
381: else if (status)
382: fprintf(stderr, "*** Interpreter exit(%d)\n", status>>8);
383: #endif SMALLSYS
384: pid = 0;
385: break;
386: }
387: }
388: #ifndef SMALLSYS
389: if (pid)
390: fprintf(stderr, "*** Can't get interpreter status\n");
391: #endif SMALLSYS
392: pid = 0;
393: }
394: }
395:
396: #endif BTOP
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.