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

Defined functions

disrupt defined in line 169; used 2 times
exec_b defined in line 145; used 1 times
expect defined in line 215; used 2 times
ffgetc defined in line 75; used 4 times
ffgets defined in line 92; never used
getdevices defined in line 109; used 1 times
intrchild defined in line 349; used 1 times
makechild defined in line 121; used 1 times
sleur defined in line 246; used 1 times
start_b defined in line 186; used 1 times
termchild defined in line 335; used 2 times
waitchild defined in line 363; used 1 times

Defined variables

Procedure defined in line 363; never used
Visible defined in line 363; never used
canjump defined in line 31; used 8 times
fdown defined in line 56; used 6 times
fup defined in line 57; used 7 times
interpreter defined in line 64; used 6 times
interrupted defined in line 30; used 7 times
jumpback defined in line 32; used 5 times
npushback defined in line 68; used 12 times
pid defined in line 59; used 15 times
pushback defined in line 67; used 7 times
rcsid defined in line 2; never used

Defined macros

ESCAPE defined in line 38; used 3 times
INTERPRETER defined in line 43; used 2 times
INTRCHILD defined in line 40; used 1 times
INTRMSG defined in line 51; used 2 times
Moreinput defined in line 54; used 1 times
RESYNC defined in line 39; used 1 times
TABS defined in line 21; used 2 times
  • in line 290(2)
Last modified: 1985-08-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1781
Valid CSS Valid XHTML 1.0 Strict