BSD 4_3_Tahoe development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Mon, 21 Mar 1988 10:27:54 +0000 (02:27 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Mon, 21 Mar 1988 10:27:54 +0000 (02:27 -0800)
Work on file usr/src/new/jove/proc.c

Synthesized-from: CSRG/cd2/4.3tahoe

usr/src/new/jove/proc.c [new file with mode: 0644]

diff --git a/usr/src/new/jove/proc.c b/usr/src/new/jove/proc.c
new file mode 100644 (file)
index 0000000..ee78996
--- /dev/null
@@ -0,0 +1,872 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "io.h"
+#include "termcap.h"
+
+#include <signal.h>
+#include <varargs.h>
+
+#ifdef MSDOS
+# include <io.h>
+# include <process.h>
+#endif
+
+
+#ifdef LINT_ARGS
+private void
+       DoShell(char *, char *),
+       com_finish(int, char *),
+       toerror(int, int),
+       closepipe(void);
+       
+private int
+       okay_error(void),
+       openforpipe(void),
+       reopenforpipe(void);
+
+private struct error
+       * AddError(struct error *, Line *, Buffer *, Line *, int);
+#else
+private void
+       DoShell(),
+       com_finish(),
+       toerror(),
+       closepipe();
+
+private int
+       openforpipe(),
+       okay_error(),
+       reopenforpipe();
+
+private struct error
+       * AddError();
+#endif
+
+
+/* This disgusting RE search string parses output from the GREP
+   family, from the pdp11 compiler, pcc, and lint.  Jay (HACK)
+   Fenlasen changed this to work for the lint errors. */
+char   ErrFmtStr[256] = "^\\{\",\\}\\([^:\"( \t]*\\)\\{\"\\, line ,:,(\\} *\\([0-9][0-9]*\\)[:)]\
+\\|::  *\\([^(]*\\)(\\([0-9]*\\))$\
+\\|( \\([^(]*\\)(\\([0-9]*\\)) ),";
+
+struct error {
+       Buffer          *er_buf;        /* Buffer error is in */
+       Line            *er_mess,       /* Actual error message */
+                       *er_text;       /* Actual error */
+       int             er_char;        /* char pos of error */
+       struct error    *er_prev,       /* List of errors */
+                       *er_next;
+};
+
+struct error   *cur_error = 0,
+               *errorlist = 0;
+Buffer         *perr_buf = 0;  /* Buffer with error messages */
+
+int    WtOnMk = 1;             /* Write the modified files when we make */
+
+/* Add an error to the end of the list of errors.  This is used for
+   parse-{C,LINT}-errors and for the spell-buffer command */
+
+private struct error *
+AddError(laste, errline, buf, line, charpos)
+struct error   *laste;
+Line   *errline,
+       *line;
+Buffer *buf;
+{
+       struct error    *new = (struct error *) emalloc(sizeof *new);
+
+       new->er_prev = laste;
+       if (laste)
+               laste->er_next = new;
+       else {
+               if (errorlist)          /* Free up old errors */
+                       ErrFree();
+               cur_error = errorlist = new;
+       }
+       laste = new;
+       new->er_next = 0;
+       new->er_buf = buf;
+       new->er_text = line;
+       new->er_char = charpos;
+       new->er_mess = errline;
+
+       return new;
+}
+
+/* Parse errors of the form specified in ErrFmtStr in the current
+   buffer.  Do a show error of the first error.  This is neat because this
+   will work for any kind of output that prints a file name and a line
+   number on the same line. */
+
+void
+ErrParse()
+{
+       Bufpos  *bp;
+       char    fname[FILESIZE],
+               lineno[10],
+               REbuf[256],
+               *REalts[10];
+       int     lnum,
+               last_lnum = -1;
+       struct error    *ep = 0;
+       Buffer  *buf,
+               *lastb = 0;
+       Line    *err_line;      
+
+       ErrFree();              /* This is important! */
+       ToFirst();
+       perr_buf = curbuf;
+       REcompile(ErrFmtStr, 1, REbuf, REalts);
+       /* Find a line with a number on it. */
+       while (bp = docompiled(FORWARD, REbuf, REalts)) {
+               SetDot(bp);
+               putmatch(1, fname, sizeof fname);
+               putmatch(2, lineno, sizeof lineno);
+               buf = do_find((Window *) 0, fname, 1);
+               if (buf != lastb) {
+                       lastb = buf;
+                       last_lnum = -1;         /* signals new file */
+                       err_line = buf->b_first;
+               }
+               (void) chr_to_int(lineno, 10, NO, &lnum);
+               if (lnum == last_lnum)  /* one error per line is nicer */
+                       continue;
+               if (last_lnum == -1)
+                       last_lnum = 1;  /* that's where we really are */
+               err_line = next_line(err_line, lnum - last_lnum);
+               ep = AddError(ep, curline, buf, err_line, 0);
+               last_lnum = lnum;
+       }
+       if (cur_error != 0)
+               ShowErr();
+}
+
+/* Free up all the errors */
+
+void
+ErrFree()
+{
+       register struct error   *ep;
+
+       for (ep = errorlist; ep != 0; ep = ep->er_next)
+               free((char *) ep);
+       errorlist = cur_error = 0;
+}
+
+/* Internal next error sets cur_error to the next error, taking the
+   argument count, supplied by the user, into consideration. */
+
+private char   errbounds[] = "You're at the %s error.",
+               noerrs[] = "No errors!";
+
+private void
+toerror(forward, num)
+{
+       register struct error   *e = cur_error;
+
+       if (e == 0)
+               complain(noerrs);
+       if ((forward && (e->er_next == 0)) ||
+           (!forward && (e->er_prev == 0)))
+               complain(errbounds, forward ? "last" : "first");
+
+       while (--num >= 0) {
+               if ((e = forward ? e->er_next : e->er_prev) == 0)
+                       break;
+               cur_error = e;
+       }
+}
+
+void
+NextError()
+{
+       ToError(1);
+}
+
+void
+PrevError()
+{
+       ToError(0);
+}
+
+private int
+okay_error()
+{
+       return ((inlist(perr_buf->b_first, cur_error->er_mess)) &&
+               (inlist(cur_error->er_buf->b_first, cur_error->er_text)));
+}
+
+/* Go the the next error, if there is one.  Put the error buffer in
+   one window and the buffer with the error in another window.
+   It checks to make sure that the error actually exists. */
+
+void
+ToError(forward)
+{
+       do {
+               toerror(forward, arg_value());
+       } while (!okay_error());
+       ShowErr();
+}
+
+int    EWSize = 20;    /* percentage of screen the error window
+                          should be */
+
+void
+set_wsize(wsize)
+int    wsize;
+{
+       wsize = (LI * wsize) / 100;
+       if (wsize >= 1 && !one_windp())
+               WindSize(curwind, wsize - (curwind->w_height - 1));
+}
+
+/* Show the current error, i.e. put the line containing the error message
+   in one window, and the buffer containing the actual error in another
+   window. */
+
+void
+ShowErr()
+{
+       Window  *err_wind,
+               *buf_wind;
+
+       if (cur_error == 0)
+               complain(noerrs);
+       if (!okay_error()) {
+               rbell();
+               return;
+       }
+       err_wind = windbp(perr_buf);
+       buf_wind = windbp(cur_error->er_buf);
+
+       if (err_wind && !buf_wind) {
+               SetWind(err_wind);
+               pop_wind(cur_error->er_buf->b_name, NO, -1);
+               buf_wind = curwind;
+       } else if (!err_wind && buf_wind) {
+               SetWind(buf_wind);
+               pop_wind(perr_buf->b_name, NO, -1);
+               err_wind = curwind;
+       } else if (!err_wind && !buf_wind) {
+               pop_wind(perr_buf->b_name, NO, -1);
+               err_wind = curwind;
+               pop_wind(cur_error->er_buf->b_name, NO, -1);
+               buf_wind = curwind;
+       }
+
+       /* Put the current error message at the top of its Window */
+       SetWind(err_wind);
+       SetLine(cur_error->er_mess);
+       SetTop(curwind, (curwind->w_line = cur_error->er_mess));
+       set_wsize(EWSize);
+
+       /* now go to the the line with the error in the other window */
+       SetWind(buf_wind);
+       DotTo(cur_error->er_text, cur_error->er_char);
+}
+
+char   ShcomBuf[128] = {0};
+
+/* Make a buffer name given the command `command', i.e. "fgrep -n foo *.c"
+   will return the buffer name "fgrep".  */
+
+char *
+MakeName(command)
+char   *command;
+{
+       static char     bufname[50];
+       register char   *cp = bufname,
+                       c;
+
+       while ((c = *command++) && (c == ' ' || c == '\t'))
+               ;
+       do
+               *cp++ = c;
+       while ((c = *command++) && (c != ' ' && c != '\t'));
+       *cp = 0;
+       strcpy(bufname, basename(bufname));
+
+       return bufname;
+}
+
+/* Run make, first writing all the modified buffers (if the WtOnMk flag is
+   non-zero), parse the errors, and go the first error. */
+
+char   make_cmd[128] = "make";
+
+void
+MakeErrors()
+{
+       Window  *old = curwind;
+       int     status,
+               compilation;
+       
+       if (WtOnMk)
+               put_bufs(0);
+       /* When we're not doing make or cc (i.e., the last command
+          was probably a grep or something) and the user just types
+          C-X C-E, he probably (possibly, hopefully, usually (in my
+          case)) doesn't want to do the grep again but rather wants
+          to do a make again; so we ring the bell and insert the
+          default command and let the person decide. */
+
+       compilation = (sindex("make", make_cmd) || sindex("cc", make_cmd));
+       if (is_an_arg() || !compilation) {
+               if (!compilation) {
+                       rbell();
+                       Inputp = make_cmd;      /* insert the default for the user */
+               }
+               null_ncpy(make_cmd, ask(make_cmd, "Compilation command: "),
+                               sizeof (make_cmd) - 1);
+       }
+       status = UnixToBuf(MakeName(make_cmd), YES, EWSize, YES, Shell, ShFlags, make_cmd, (char *) 0);
+       com_finish(status, make_cmd);
+
+       ErrParse();
+
+       if (!cur_error)
+               SetWind(old);
+}
+
+#ifdef SPELL
+
+void
+SpelBuffer()
+{
+       char    *Spell = "Spell",
+               com[100];
+       Window  *savewp = curwind;
+
+       put_bufs(0);
+       sprintf(com, "spell %s", curbuf->b_fname);
+       (void) UnixToBuf(Spell, YES, EWSize, YES, Shell, ShFlags, com, (char *) 0);
+       message("[Delete the irrelevant words and then type C-X C-C]");
+       ToFirst();
+       Recur();
+       SetWind(savewp);
+       SpelParse(Spell);
+}
+
+void
+SpelWords()
+{
+       char    *buftospel;
+       Buffer  *wordsb = curbuf;
+
+       if ((buftospel = ask_buf((Buffer *) 0)) == 0)
+               return;
+       SetBuf(do_select(curwind, buftospel));
+       SpelParse(wordsb->b_name);
+}
+
+void
+SpelParse(bname)
+char   *bname;
+{
+       Buffer  *buftospel,
+               *wordsb;
+       char    wordspel[100];
+       Bufpos  *bp;
+       struct error    *ep = 0;
+
+       ErrFree();              /* This is important! */
+
+       buftospel = curbuf;
+       wordsb = buf_exists(bname);
+       perr_buf = wordsb;      /* This is important (buffer containing
+                                  error messages) */
+       SetBuf(wordsb);
+       ToFirst();
+       f_mess("Finding misspelled words ... ");
+       while (!lastp(curline)) {
+               sprintf(wordspel, "\\<%s\\>", linebuf);
+               SetBuf(buftospel);
+               ToFirst();
+               while (bp = dosearch(wordspel, 1, 1)) {
+                       SetDot(bp);
+                       ep = AddError(ep, wordsb->b_dot, buftospel,
+                                         curline, curchar);
+               }
+               SetBuf(wordsb);
+               line_move(FORWARD, 1, NO);
+       }
+       add_mess("Done.");
+       SetBuf(buftospel);
+       ShowErr();
+}
+
+#endif /* SPELL */
+
+void
+ShToBuf()
+{
+       char    bufname[128],
+               cmd[128];
+
+       strcpy(bufname, ask((char *) 0, "Buffer: "));
+       strcpy(cmd, ask(ShcomBuf, "Command: "));
+       DoShell(bufname, cmd);
+}
+
+void
+ShellCom()
+{
+       null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1);
+       DoShell(MakeName(ShcomBuf), ShcomBuf);
+}
+
+ShNoBuf()
+{
+       int     status;
+
+       null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1);
+       status = UnixToBuf((char *) 0, NO, 0, NO, Shell, ShFlags, ShcomBuf, (char *) 0);
+       com_finish(status, ShcomBuf);
+}
+
+Shtypeout()
+{
+       int     status;
+
+       null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1);
+       status = UnixToBuf((char *) 0, YES, 0, NO, Shell, ShFlags, ShcomBuf, (char *) 0);
+       if (status == 0)
+               Typeout("[%s: completed successfully]", ShcomBuf);
+       else
+               Typeout("[%s: exited (%d)]", ShcomBuf, status);
+       TOstop();
+}
+
+/* Run the shell command into `bufname'.  Empty the buffer except when we
+   give a numeric argument, in which case it inserts the output at the
+   current position in the buffer.  */
+
+private void
+DoShell(bufname, command)
+char   *bufname,
+       *command;
+{
+       Window  *savewp = curwind;
+       int     status;
+
+       status = UnixToBuf(bufname, YES, 0, !is_an_arg(), Shell,
+                          ShFlags, command, (char *) 0);
+       com_finish(status, command);
+       SetWind(savewp);
+}
+
+private void
+com_finish(status, cmd)
+int    status;
+char   *cmd;
+{
+       s_mess("[%s: ", cmd);
+       if (status == 0)
+               add_mess("completed successfully");
+       else
+               add_mess("exited (%d)", status);
+       add_mess("]");
+}
+
+#ifndef MSDOS
+void
+dowait(pid, status)
+int    pid,
+       *status;
+{
+# ifndef IPROCS
+
+       int     rpid;
+
+       while ((rpid = wait(status)) != pid)
+               ;
+# else
+
+#  ifdef BSD4_2
+#   include <sys/wait.h>
+#  else
+#   include <wait.h>
+#  endif
+
+       union wait      w;
+       int     rpid;
+
+       for (;;) {
+#  ifndef BSD4_2
+               rpid = wait2(&w.w_status, 0);
+#  else
+               rpid = wait3(&w, 0, (struct rusage *) 0);
+#  endif
+               if (rpid == pid) {
+                       if (status)
+                               *status = w.w_status;
+                       break;
+               } else
+                       kill_off(rpid, w);
+       }
+# endif /* IPROCS */
+}
+#endif /* MSDOS */
+
+/* Run the command to bufname, erase the buffer if clobber is non-zero,
+   and redisplay if disp is non-zero.  Leaves current buffer in `bufname'
+   and leaves any windows it creates lying around.  It's up to the caller
+   to fix everything up after we're done.  (Usually there's nothing to
+   fix up.) */
+
+/* VARARGS5 */
+
+int
+UnixToBuf(bufname, disp, wsize, clobber, va_alist)
+char   *bufname;
+va_dcl
+{
+#ifndef MSDOS
+       int     p[2],
+               pid,
+               status,
+#else /* MSDOS */
+       int     p0,
+               oldo,
+               olde,
+               retcode,
+#endif /* MSDOS */
+               eof;
+       va_list ap;
+       char    *argv[32],
+               *mess;
+       File    *fp;
+       int     (*old_int)();
+
+       va_start(ap);
+       make_argv(argv, ap);
+       va_end(ap);
+       if (bufname != 0 && clobber == YES)
+               isprocbuf(bufname);
+       if (disp) {
+               if (bufname != 0)
+                       message("Starting up...");
+               else {
+                       TOstart(argv[0], TRUE);
+                       Typeout("Starting up...");
+               }
+               if (bufname != 0) {
+                       pop_wind(bufname, clobber, clobber ? B_PROCESS : B_FILE);
+                       set_wsize(wsize);
+                       redisplay();
+               }
+       }
+       /* Now I will attempt to describe how I deal with signals during
+          the execution of the shell command.  My desire was to be able
+          to interrupt the shell command AS SOON AS the window pops up.
+          So, if we have JOB_CONTROL (i.e., the new signal mechanism) I
+          hold SIGINT, meaning if we interrupt now, we will eventually
+          see the interrupt, but not before we are ready for it.  We
+          fork, the child releases the interrupt, it then sees the
+          interrupt, and so exits.  Meanwhile the parent ignores the
+          signal, so if there was a pending one, it's now lost.
+
+          With no JOB_CONTROL, the best behavior you can expect is, when
+          you type ^] too very quickly after the window pops up, it may
+          be ignored.  The behavior BEFORE was that it would interrupt
+          JOVE and then you would have to continue JOVE and wait a
+          little while longer before trying again.  Now that is fixed,
+          in that you just have to type it twice. */
+
+#ifndef MSDOS
+# ifdef IPROCS
+       sighold(SIGCHLD);
+# endif
+# ifdef JOB_CONTROL
+       sighold(SIGINT);
+# else
+       old_int = signal(SIGINT, SIG_IGN),
+# endif
+       dopipe(p);
+       pid = fork();
+       if (pid == -1) {
+               pclose(p);
+               complain("[Fork failed]");
+       }
+       if (pid == 0) {
+# ifdef IPROCS
+               sigrelse(SIGCHLD);   /* don't know if this matters */
+# endif /* IPROCS */
+               (void) signal(SIGINT, SIG_DFL);
+# ifdef JOB_CONTROL
+               sigrelse(SIGINT);
+# endif
+               (void) close(0);
+               (void) open("/dev/null", 0);
+               (void) close(1);
+               (void) close(2);
+               (void) dup(p[1]);
+               (void) dup(p[1]);
+               pclose(p);
+               execv(argv[0], &argv[1]);
+               (void) write(1, "Execl failed.\n", 14);
+               _exit(1);
+       }
+# ifdef JOB_CONTROL
+       old_int = signal(SIGINT, SIG_IGN);
+# endif        
+       (void) close(p[1]);
+       fp = fd_open(argv[1], F_READ, p[0], iobuff, LBSIZE);
+#else /* MSDOS */
+       if ((p0 = openforpipe()) < 0)
+          complain("cannot make pipe for filter");
+
+       oldo = dup(1);
+       olde = dup(2);
+       close(1);
+       close(2);
+       dup(p0);
+       dup(1);
+       close(p0);
+       retcode = spawnv(0, argv[0], &argv[1]);
+       p0 = reopenforpipe();
+       close(1);
+       close(2);
+       dup(oldo);
+       dup(olde);
+       close(oldo);
+       close(olde);
+
+       if (retcode < 0)
+               complain("[Spawn failed]");
+
+       fp = fd_open(argv[1], F_READ, p0, iobuff, LBSIZE);
+#endif /* MSDOS */
+       do {
+#ifndef MSDOS
+               inIOread = 1;
+#endif
+               eof = f_gets(fp, genbuf, LBSIZE);
+#ifndef MSDOS
+               inIOread = 0;
+#endif
+               if (bufname != 0) {
+                       ins_str(genbuf, YES);
+                       if (!eof)
+                               LineInsert(1);
+               } else if (disp == YES)
+                       Typeout("%s", genbuf);
+               if (bufname != 0 && disp != 0 && fp->f_cnt <= 0) {
+#ifdef LOAD_AV
+                   {
+                       double  theavg;
+
+                       get_la(&theavg);
+                       if (theavg < 2.0)
+                               mess = "Screaming along...";
+                       else if (theavg < 5.0)
+                               mess = "Chugging along...";
+                       else
+                               mess = "Crawling along...";
+                   }
+#else
+                       mess = "Chugging along...";
+#endif /* LOAD_AV */
+                       if (bufname != 0) {
+                               message(mess);
+                               redisplay();
+                       }
+               }
+       } while (!eof);
+       if (disp)
+               DrawMesg(NO);
+       close_file(fp);
+#ifndef MSDOS
+       dowait(pid, &status);
+# ifdef JOB_CONTROL
+       (void) sigrelse(SIGINT);
+# endif
+#else /* MSDOS */
+       closepipe();
+#endif /* MSDOS */
+       (void) signal(SIGINT, old_int);
+#ifndef MSDOS
+# ifdef IPROCS
+       sigrelse(SIGCHLD);
+# endif
+       return status;
+#else /* MSDOS */
+# ifdef CHDIR
+       getCWD();
+# endif        
+       return retcode;
+#endif /* MSDOS */
+}
+
+#ifndef MSDOS
+#ifdef BSD4_2
+
+private long   SigMask = 0;
+
+#ifndef sigmask
+#      define  sigmask(s)      (1L << ((s)-1))
+#endif
+
+sighold(sig)
+{
+       (void) sigblock(SigMask |= sigmask(sig));
+}
+
+sigrelse(sig)
+{
+       (void) sigsetmask(SigMask &= ~sigmask(sig));
+}
+
+#endif
+
+#endif /* MSDOS */
+
+void
+FilterRegion()
+{
+       char    *cmd = ask((char *) 0, ": %f (through command) ", ProcFmt);
+
+       RegToUnix(curbuf, cmd);
+}
+
+/* Send the current region to CMD and insert the output from the
+   command into OUT_BUF. */
+
+void
+RegToUnix(outbuf, cmd)
+Buffer *outbuf;
+char   *cmd;
+{
+       Mark    *m = CurMark();
+#ifndef MSDOS
+       char    *tname = mktemp("/tmp/jfilterXXXXXX"),
+               combuf[128];
+#endif /* MSDOS */
+       Window  *save_wind = curwind;
+       int     status,
+               error = NO;
+#ifdef MSDOS
+       int p0, oldi;
+#endif /* MSDOS */
+       File    *fp;
+
+#ifndef MSDOS
+       fp = open_file(tname, iobuff, F_WRITE, COMPLAIN, QUIET);
+#else /* MSDOS */
+       p0 = openforpipe();
+#endif /* MSDOS */
+    CATCH
+#ifdef MSDOS
+       fp = fd_open(cmd, F_WRITE, p0, iobuff, LBSIZE);
+#endif /* MSDOS */
+       putreg(fp, m->m_line, m->m_char, curline, curchar, YES);
+       DelReg();
+#ifndef MSDOS
+       sprintf(combuf, "%s < %s", cmd, tname);
+#else /* MSDOS */
+       f_close(fp);
+       p0 = reopenforpipe();
+    oldi = dup(0);
+       close(0);
+       dup(p0);
+       close(p0);
+#endif /* MSDOS */
+       status = UnixToBuf(outbuf->b_name, NO, 0, outbuf->b_type == B_SCRATCH,
+#ifndef MSDOS
+                          Shell, ShFlags, combuf, (char *) 0);
+#else /* MSDOS */
+                          Shell, ShFlags, cmd, (char *) 0);
+#endif /* MSDOS */
+    ONERROR
+       error = YES;
+    ENDCATCH
+#ifndef MSDOS
+       f_close(fp);
+       (void) unlink(tname);
+#else /* MSDOS */
+       close(0);
+       open("con", 0); /* dup(oldi);   */
+       close(oldi);
+       closepipe();
+#endif /* MSDOS */
+       SetWind(save_wind);
+       if (error == NO)
+#ifndef MSDOS
+               com_finish(status, combuf);
+#else
+               com_finish(status, cmd);
+#endif
+}
+
+void
+isprocbuf(bufname)
+char   *bufname;
+{
+       Buffer  *bp;
+
+       if ((bp = buf_exists(bufname)) != 0 && bp->b_type != B_PROCESS)
+               confirm("Over-write buffer %s?", bufname);
+}
+
+#ifdef MSDOS
+/*     msdos specific hacks to allow for pipes */
+
+#include <dos.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static char pipeiname[64];
+static char pipeoname[64];
+static int  pipehandle;
+
+extern char TmpFilePath[];
+
+private int
+openforpipe()
+{
+   sprintf(pipeiname, "%s/%s", TmpFilePath, "Jove-I");
+   sprintf(pipeoname, "%s/%s", TmpFilePath, "Jove-O");
+
+   return(pipehandle = creat(pipeoname, S_IWRITE|S_IREAD));
+}
+
+private int
+reopenforpipe()
+{                     
+   close(pipehandle);
+   unlink(pipeiname);
+   rename(pipeoname, pipeiname);
+   if ((pipehandle = open(pipeiname, 0)) >= 0)
+      return(pipehandle);
+   closepipe();
+   return(-1);
+}
+
+private void
+closepipe()
+{       
+   unlink(pipeoname);
+   unlink(pipeiname);
+}
+         
+char 
+switchar()
+{
+  union REGS regs;
+  
+  regs.h.ah = 0x37;
+  regs.h.al = 0;   
+  intdos(&regs, &regs);
+  return(regs.h.dl);
+}
+#endif /* MSDOS */