home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / ip_cl / ip_cl.c next >
C/C++ Source or Header  |  1996-10-13  |  13KB  |  743 lines

  1. /*-
  2.  * Copyright (c) 1996
  3.  *    Keith Bostic.  All rights reserved.
  4.  *
  5.  * See the LICENSE file for redistribution information.
  6.  */
  7.  
  8. #include "config.h"
  9.  
  10. #ifndef lint
  11. static const char sccsid[] = "@(#)ip_cl.c    8.4 (Berkeley) 10/13/96";
  12. #endif /* not lint */
  13.  
  14. #include <sys/types.h>
  15. #include <sys/ioctl.h>
  16. #include <sys/queue.h>
  17. #include <sys/select.h>
  18.  
  19. #include <bitstring.h>
  20. #include <ctype.h>
  21. #include <curses.h>
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <signal.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29.  
  30. #include "../common/common.h"
  31. #include "../ip/ip.h"
  32. #include "pathnames.h"
  33.  
  34. size_t    cols, rows;                /* Screen columns, rows. */
  35. int    die;                    /* Child died. */
  36. int    i_fd, o_fd;                /* Input/output fd's. */
  37. int    resize;                    /* Window resized. */
  38.  
  39. void    arg_format __P((int *, char **[], int, int));
  40. void    attach __P((void));
  41. void    ip_cur_end __P((void));
  42. void    ip_cur_init __P((void));
  43. void    ip_read __P((void));
  44. void    ip_resize __P((void));
  45. int    ip_send __P((char *, IP_BUF *));
  46. void    ip_siginit __P((void));
  47. int    ip_trans __P((char *, size_t, size_t *));
  48. void    nomem __P((void));
  49. void    onchld __P((int));
  50. void    onintr __P((int));
  51. void    onwinch __P((int));
  52. void    trace __P((const char *, ...));
  53. void    usage __P((void));
  54.  
  55. int
  56. main(argc, argv)
  57.     int argc;
  58.     char *argv[];
  59. {
  60.     fd_set fdset;
  61.     pid_t pid;
  62.     size_t blen, len, skip;
  63.     int ch, nr, rpipe[2], wpipe[2];
  64.     char *bp;
  65.  
  66.     while ((ch = getopt(argc, argv, "D")) != EOF)
  67.         switch (ch) {
  68.         case 'D':
  69.             attach();
  70.             break;
  71.         case '?':
  72.         default:
  73.             usage();
  74.         }
  75.     argc -= optind;
  76.     argv += optind;
  77.  
  78.     /*
  79.      * Open the communications pipes.  The pipes are named from our
  80.      * viewpoint, so we read from rpipe[0] and write to wpipe[1].
  81.      * Vi reads from wpipe[0], and writes to rpipe[1].
  82.      */
  83.     if (pipe(rpipe) == -1 || pipe(wpipe) == -1) {
  84.         perror("ip_cl: pipe");
  85.         exit (1);
  86.     }
  87.     i_fd = rpipe[0];
  88.     o_fd = wpipe[1];
  89.  
  90.     /*
  91.      * Format our arguments, adding a -I to the list.  The first file
  92.      * descriptor to the -I argument is vi's input, and the second is
  93.      * vi's output.
  94.      */
  95.     arg_format(&argc, &argv, wpipe[0], rpipe[1]);
  96.  
  97.     /* Run vi. */
  98.     switch (pid = fork()) {
  99.     case -1:                /* Error. */
  100.         perror("ip_cl: fork");
  101.         exit (1);
  102.     case 0:                    /* Vi. */
  103.         execv(VI, argv);
  104.         perror("ip_cl: execv ../build/nvi");
  105.         exit (1);
  106.     default:                /* Ip_cl. */
  107.         break;
  108.     }
  109.  
  110.     /*
  111.      * Allocate initial input buffer.
  112.      * XXX
  113.      * We don't dynamically resize, so there better not be any individual
  114.      * messages larger than this buffer.
  115.      */
  116.     blen = 4 * 1024;
  117.     if ((bp = malloc(blen)) == NULL)
  118.         nomem();
  119.  
  120.     /* Clear the file descriptor mask. */
  121.     FD_ZERO(&fdset);
  122.  
  123.     /* Initialize signals. */
  124.     ip_siginit();
  125.  
  126.     /* Initialize the curses screen. */
  127.     ip_cur_init();
  128.  
  129.     /* The first thing vi wants is the screen size. */
  130.     ip_resize();
  131.  
  132.     /* Main loop. */
  133.     for (len = 0;;) {
  134.         if (die)
  135.             break;
  136.         /*
  137.          * XXX
  138.          * Race #1: if there's an event coming from vi that requires
  139.          * that we know what size the screen is, and we take a resize
  140.          * signal, we'll differ from vi in the size of the screen for
  141.          * that event.  Fixing this will requires information attached
  142.          * to message as to what set of state was in place when the
  143.          * message was sent.  Not hard, but not worth doing now.
  144.          *
  145.          * Race #2: we cycle, handling resize events until there aren't
  146.          * any waiting.  We then do a select.  If the resize signal
  147.          * arrives after we exit the loop but before we enter select,
  148.          * we'll wait on the user to enter a keystroke, handle it and
  149.          * then handle the resize.
  150.          */
  151.         while (resize) {
  152.             resize = 0;
  153.             ip_resize();
  154.             ip_cur_end();
  155.             ip_cur_init();
  156.         }
  157.  
  158.         /* Wait until vi or the screen wants to talk. */
  159.         FD_SET(i_fd, &fdset);
  160.         FD_SET(STDIN_FILENO, &fdset);
  161.         errno = 0;
  162.         switch (select(i_fd + 1, &fdset, NULL, NULL, NULL)) {
  163.         case 0:
  164.             abort();        /* Timeout. */
  165.             /* NOTREACHED */
  166.         case -1:
  167.             if (errno == EINTR)
  168.                 continue;
  169.             perror("ip_cl: select");
  170.             exit (1);
  171.         default:
  172.             break;
  173.         }
  174.  
  175.         /* Read waiting tty characters and send them to vi. */
  176.         if (FD_ISSET(STDIN_FILENO, &fdset)) {
  177.             ip_read();
  178.             continue;
  179.         }
  180.  
  181.         /* Read waiting vi messages and translate to curses calls. */
  182.         switch (nr = read(i_fd, bp + len, blen - len)) {
  183.         case 0:
  184.             continue;
  185.         case -1:
  186.             perror("ip_cl: read");
  187.             exit (1);
  188.         default:
  189.             break;
  190.         }
  191.  
  192.         /* Parse to data end or partial message. */
  193.         for (len += nr, skip = 0; len > skip &&
  194.             ip_trans(bp + skip, len - skip, &skip) == 1;);
  195.  
  196.         /* Copy any partial messages down in the buffer. */
  197.         len -= skip;
  198.         if (len > 0)
  199.             memmove(bp, bp + skip, len);
  200.     }
  201.  
  202.     /* End the screen. */
  203.     ip_cur_end();
  204.  
  205.     exit (0);
  206. }
  207.  
  208. /*
  209.  * ip_read --
  210.  *    Read characters from the screen and send them to vi.
  211.  */
  212. void
  213. ip_read()
  214. {
  215.     IP_BUF ipb;
  216.     int nr;
  217.     char bp[1024];
  218.  
  219.     /* Read waiting tty characters. */
  220.     switch (nr = read(STDIN_FILENO, bp, sizeof(bp))) {
  221.     case 0:
  222.         return;
  223.     case -1:
  224.         perror("ip_cl: read");
  225.         exit (1);
  226.     default:
  227.         break;
  228.     }
  229.  
  230.     ipb.code = IPO_STRING;
  231.     ipb.len = nr;
  232.     ipb.str = bp;
  233.     ip_send("s", &ipb);
  234. }
  235.  
  236. /*
  237.  * ip_trans --
  238.  *    Translate vi messages into curses calls.
  239.  */
  240. int
  241. ip_trans(bp, len, skipp)
  242.     char *bp;
  243.     size_t len, *skipp;
  244. {
  245.     IP_BUF ipb;
  246.     size_t cno, lno, nlen, oldy, oldx, spcnt;
  247.     int ch;
  248.     char *fmt, *p;
  249.  
  250.     switch (bp[0]) {
  251.     case IPO_ADDSTR:
  252.     case IPO_RENAME:
  253.         fmt = "s";
  254.         break;
  255.     case IPO_BUSY:
  256.         fmt = "s1";
  257.         break;
  258.     case IPO_ATTRIBUTE:
  259.     case IPO_MOVE:
  260.         fmt = "12";
  261.         break;
  262.     case IPO_REWRITE:
  263.         fmt = "1";
  264.         break;
  265.     default:
  266.         fmt = "";
  267.     }
  268.  
  269.     nlen = IPO_CODE_LEN;
  270.     p = bp + IPO_CODE_LEN;
  271.     for (; *fmt != '\0'; ++fmt)
  272.         switch (*fmt) {
  273.         case '1':
  274.             nlen += IPO_INT_LEN;
  275.             if (len < nlen)
  276.                 return (0);
  277.             memcpy(&ipb.val1, p, IPO_INT_LEN);
  278.             ipb.val1 = ntohl(ipb.val1);
  279.             p += IPO_INT_LEN;
  280.             break;
  281.         case '2':
  282.             nlen += IPO_INT_LEN;
  283.             if (len < nlen)
  284.                 return (0);
  285.             memcpy(&ipb.val2, p, IPO_INT_LEN);
  286.             ipb.val2 = ntohl(ipb.val2);
  287.             p += IPO_INT_LEN;
  288.             break;
  289.         case 's':
  290.             nlen += IPO_INT_LEN;
  291.             if (len < nlen)
  292.                 return (0);
  293.             memcpy(&ipb.len, p, IPO_INT_LEN);
  294.             ipb.len = ntohl(ipb.len);
  295.             p += IPO_INT_LEN;
  296.             nlen += ipb.len;
  297.             if (len < nlen)
  298.                 return (0);
  299.             ipb.str = p;
  300.             p += ipb.len;
  301.             break;
  302.         }
  303.     *skipp += nlen;
  304.  
  305.     switch (bp[0]) {
  306.     case IPO_ADDSTR:
  307. #ifdef TR
  308.         trace("addnstr {%.*s}\n", (int)ipb.len, ipb.str);
  309. #endif
  310.         (void)addnstr(ipb.str, ipb.len);
  311.         break;
  312.     case IPO_ATTRIBUTE:
  313.         switch (ipb.val1) {
  314.         case SA_ALTERNATE:
  315. #ifdef TR
  316.             trace("attr: alternate\n");
  317. #endif
  318.             /*
  319.              * XXX
  320.              * Nothing.
  321.              */
  322.             break;
  323.         case SA_INVERSE:
  324. #ifdef TR
  325.             trace("attr: inverse\n");
  326. #endif
  327.             if (ipb.val2)
  328.                 (void)standout();
  329.             else
  330.                 (void)standend();
  331.             break;
  332.         default:
  333.             abort();
  334.             /* NOTREACHED */
  335.         }
  336.         break;
  337.     case IPO_BELL:
  338. #ifdef TR
  339.         trace("bell\n");
  340. #endif
  341.         (void)write(1, "\007", 1);        /* '\a' */
  342.         break;
  343.     case IPO_BUSY:
  344. #ifdef TR
  345.         trace("busy {%.*s}\n", (int)ipb.len, ipb.str);
  346. #endif
  347.         /*
  348.          * XXX
  349.          * Nothing...
  350.          * ip_busy(ipb.str, ipb.len);
  351.          */
  352.         break;
  353.     case IPO_CLRTOEOL:
  354. #ifdef TR
  355.         trace("clrtoeol\n");
  356. #endif
  357.         clrtoeol();
  358.         break;
  359.     case IPO_DELETELN:
  360. #ifdef TR
  361.         trace("deleteln\n");
  362. #endif
  363.         deleteln();
  364.         break;
  365.     case IPO_INSERTLN:
  366. #ifdef TR
  367.         trace("insertln\n");
  368. #endif
  369.         insertln();
  370.         break;
  371.     case IPO_MOVE:
  372. #ifdef TR
  373.         trace("move: %lu %lu\n", (u_long)ipb.val1, (u_long)ipb.val2);
  374. #endif
  375.         (void)move(ipb.val1, ipb.val2);
  376.         break;
  377.     case IPO_REDRAW:
  378. #ifdef TR
  379.         trace("redraw\n");
  380. #endif
  381.         clearok(curscr, 1);
  382.         refresh();
  383.         break;
  384.     case IPO_REFRESH:
  385. #ifdef TR
  386.         trace("refresh\n");
  387. #endif
  388.         refresh();
  389.         break;
  390.     case IPO_RENAME:
  391. #ifdef TR
  392.         trace("rename {%.*s}\n", (int)ipb.len, ipb.str);
  393. #endif
  394.         /*
  395.          * XXX
  396.          * Nothing...
  397.          * ip_rename(ipb.str, ipb.len);
  398.          */
  399.         break;
  400.     case IPO_REWRITE:
  401. #ifdef TR
  402.         trace("rewrite {%lu}\n", (u_long)ipb.val1);
  403. #endif
  404.         getyx(stdscr, oldy, oldx);
  405.         for (lno = ipb.val1, cno = spcnt = 0;;) {
  406.             (void)move(lno, cno);
  407.             ch = winch(stdscr);
  408.             if (isblank(ch))
  409.                 ++spcnt;
  410.             else {
  411.                 (void)move(lno, cno - spcnt);
  412.                 for (; spcnt > 0; --spcnt)
  413.                     (void)addch(' ');
  414.                 (void)addch(ch);
  415.             }
  416.             if (++cno >= cols)
  417.                 break;
  418.         }
  419.         (void)move(oldy, oldx);
  420.         break;
  421.     default:
  422.         /*
  423.          * XXX: Protocol is out of sync?  
  424.          */
  425.         abort();
  426.     }
  427.  
  428.     return (1);
  429. }
  430.  
  431. /*
  432.  * arg_format
  433.  */
  434. void
  435. arg_format(argcp, argvp, i_fd, o_fd)
  436.     int *argcp, i_fd, o_fd;
  437.     char **argvp[];
  438. {
  439.     char **largv, *iarg, *p;
  440.  
  441.     /* Get space for the argument array and the -I argument. */
  442.     if ((iarg = malloc(64)) == NULL ||
  443.         (largv = malloc((*argcp + 3) * sizeof(char *))) == NULL) {
  444.         perror("ip_cl");
  445.         exit (1);
  446.     }
  447.     memcpy(largv + 2, *argvp, *argcp * sizeof(char *) + 1);
  448.  
  449.     /* Reset argv[0] to be the exec'd program. */
  450.     if ((p = strrchr(VI, '/')) == NULL)
  451.         largv[0] = VI;
  452.     else
  453.         largv[0] = p + 1;
  454.  
  455.     /* Create the -I argument. */
  456.     (void)sprintf(iarg, "-I%d%s%d", i_fd, ".", o_fd);
  457.     largv[1] = iarg;
  458.  
  459.     /* Reset the argument array. */
  460.     *argvp = largv;
  461. }
  462.  
  463. /*
  464.  * ip_cur_init --
  465.  *    Initialize the curses screen.
  466.  */
  467. void
  468. ip_cur_init()
  469. {
  470.     /* 
  471.      * XXX
  472.      * This is 4BSD curses' specific -- if this is to be a real program
  473.      * we'll have to do all the stuff that we do in the cl directory to
  474.      * run with different curses variants.
  475.      */
  476.     if (initscr() == ERR) {
  477.         perror("ip_cl: initscr");
  478.         exit (1);
  479.     }
  480.     noecho();
  481.     nonl();
  482.     raw();
  483.     idlok(stdscr, 1);
  484. }
  485.  
  486. /*
  487.  * ip_cur_end --
  488.  *    End the curses screen.
  489.  */
  490. void
  491. ip_cur_end()
  492. {
  493.     (void)move(0, 0);
  494.     (void)deleteln();
  495.     (void)move(rows - 1, 0);
  496.     (void)refresh();
  497.     (void)endwin();
  498. }
  499.  
  500. /*
  501.  * ip_siginit --
  502.  *    Initialize the signals.
  503.  */
  504. void
  505. ip_siginit()
  506. {
  507.     /* We need to know if vi dies horribly. */
  508.     (void)signal(SIGCHLD, onchld);
  509.  
  510.     /* We want to allow interruption at least for now. */
  511.     (void)signal(SIGINT, onintr);
  512.  
  513. #ifdef SIGWINCH
  514.     /* We need to know if the screen is resized. */
  515.     (void)signal(SIGWINCH, onwinch);
  516. #endif
  517. }
  518.  
  519. /*
  520.  * ip_resize --
  521.  *    Send the window size.
  522.  */
  523. void
  524. ip_resize()
  525. {
  526.     struct winsize win;
  527.     IP_BUF ipb;
  528.  
  529.     if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) == -1) {
  530.         perror("ip_cl: TIOCGWINSZ");
  531.         exit(1);
  532.     }
  533.  
  534.     if (rows == win.ws_row && cols == win.ws_col)
  535.         return;
  536.  
  537.     ipb.val1 = rows = win.ws_row;
  538.     ipb.val2 = cols = win.ws_col;
  539.     ipb.code = IPO_RESIZE;
  540.     ip_send("12", &ipb);
  541. }
  542.  
  543. /*
  544.  * ip_send --
  545.  *    Construct and send an IP buffer.
  546.  */
  547. int
  548. ip_send(fmt, ipbp)
  549.     char *fmt;
  550.     IP_BUF *ipbp;
  551. {
  552.     static char *bp;
  553.     static size_t blen;
  554.     size_t off;
  555.     u_int32_t ilen;
  556.     int nlen, n, nw;
  557.     char *p;
  558.     
  559.     if (blen == 0 && (bp = malloc(blen = 512)) == NULL)
  560.         nomem();
  561.  
  562.     p = bp;
  563.     nlen = 0;
  564.     *p++ = ipbp->code;
  565.     nlen += IPO_CODE_LEN;
  566.  
  567.     if (fmt != NULL)
  568.         for (; *fmt != '\0'; ++fmt)
  569.             switch (*fmt) {
  570.             case '1':            /* Value 1. */
  571.                 ilen = htonl(ipbp->val1);
  572.                 goto value;
  573.             case '2':            /* Value 2. */
  574.                 ilen = htonl(ipbp->val2);
  575. value:                nlen += IPO_INT_LEN;
  576.                 if (nlen >= blen) {
  577.                     blen = blen * 2 + nlen;
  578.                     off = p - bp;
  579.                     if ((bp = realloc(bp, blen)) == NULL)
  580.                         nomem();
  581.                     p = bp + off;
  582.                 }
  583.                 memmove(p, &ilen, IPO_INT_LEN);
  584.                 p += IPO_INT_LEN;
  585.                 break;
  586.             case 's':            /* String. */
  587.                 ilen = ipbp->len;    /* XXX: conversion. */
  588.                 ilen = htonl(ilen);
  589.                 nlen += IPO_INT_LEN + ipbp->len;
  590.                 if (nlen >= blen) {
  591.                     blen = blen * 2 + nlen;
  592.                     off = p - bp;
  593.                     if ((bp = realloc(bp, blen)) == NULL)
  594.                         nomem();
  595.                     p = bp + off;
  596.                 }
  597.                 memmove(p, &ilen, IPO_INT_LEN);
  598.                 p += IPO_INT_LEN;
  599.                 memmove(p, ipbp->str, ipbp->len);
  600.                 p += ipbp->len;
  601.                 break;
  602.             }
  603. #ifdef TR
  604.     trace("WROTE: ");
  605.     for (n = p - bp, p = bp; n > 0; --n, ++p)
  606.         if (isprint(*p))
  607.             (void)trace("%c", *p);
  608.         else
  609.             trace("<%x>", (u_char)*p);
  610.     trace("\n");
  611. #endif
  612.  
  613.     for (n = p - bp, p = bp; n > 0; n -= nw, p += nw)
  614.         if ((nw = write(o_fd, p, n)) < 0) {
  615.             perror("ip_cl: write");
  616.             exit(1);
  617.         }
  618.  
  619.     return (0);
  620. }
  621.  
  622. void
  623. nomem()
  624. {
  625.     perror("ip_cl");
  626.     exit (1);
  627. }
  628.  
  629. /*
  630.  * onchld --
  631.  *    Handle SIGCHLD.
  632.  */
  633. void
  634. onchld(signo)
  635.     int signo;
  636. {
  637.     die = 1;
  638.  
  639. #ifdef TR
  640.     trace("SIGCHLD\n");
  641. #endif
  642.  
  643.     /* Interrupt select if it's running. */
  644.     (void)kill(getpid(), SIGINT);
  645. }
  646.  
  647. /*
  648.  * onintr --
  649.  *    Handle SIGINT.
  650.  */
  651. void
  652. onintr(signo)
  653.     int signo;
  654. {
  655.     /*
  656.      * If we receive an interrupt, we may have sent it ourselves.
  657.      * If not, die from the signal.
  658.      */
  659.     if (die)
  660.         return;
  661.     (void)signal(SIGINT, SIG_DFL);
  662.     kill(getpid(), SIGINT);
  663. }
  664.  
  665. /*
  666.  * onwinch --
  667.  *    Handle SIGWINCH.
  668.  */
  669. void
  670. onwinch(signo)
  671.     int signo;
  672. {
  673.     resize = 1;
  674. }
  675.  
  676. void
  677. attach()
  678. {
  679.     int fd;
  680.     char ch;
  681.  
  682.     (void)printf("process %lu waiting, enter <CR> to continue: ",
  683.         (u_long)getpid());
  684.     (void)fflush(stdout);
  685.  
  686.     if ((fd = open(_PATH_TTY, O_RDONLY, 0)) < 0) {
  687.         perror(_PATH_TTY);
  688.         exit (1);;
  689.     }
  690.     do {
  691.         if (read(fd, &ch, 1) != 1) {
  692.             (void)close(fd);
  693.             return;
  694.         }
  695.     } while (ch != '\n' && ch != '\r');
  696.     (void)close(fd);
  697. }
  698.  
  699. #ifdef TR
  700. #ifdef __STDC__
  701. #include <stdarg.h>
  702. #else
  703. #include <varargs.h>
  704. #endif
  705.  
  706. /*
  707.  * TR --
  708.  *    debugging trace routine.
  709.  */
  710. void
  711. #ifdef __STDC__
  712. trace(const char *fmt, ...)
  713. #else
  714. trace(fmt, va_alist)
  715.     char *fmt;
  716.     va_dcl
  717. #endif
  718. {
  719.     static FILE *tfp;
  720.     va_list ap;
  721.  
  722.     if (tfp == NULL && (tfp = fopen(TR, "w")) == NULL)
  723.         tfp = stderr;
  724.     
  725. #ifdef __STDC__
  726.     va_start(ap, fmt);
  727. #else
  728.     va_start(ap);
  729. #endif
  730.     (void)vfprintf(tfp, fmt, ap);
  731.     va_end(ap);
  732.  
  733.     (void)fflush(tfp);
  734. }
  735. #endif
  736.  
  737. void
  738. usage()
  739. {
  740.     (void)fprintf(stderr, "usage: ip_cl [-D]\n");
  741.     exit(1);
  742. }
  743.