|
|
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.