diff options
author | peter <peter@FreeBSD.org> | 1996-11-01 06:45:43 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1996-11-01 06:45:43 +0000 |
commit | 59cc89c2c2e686da3bdab2d5cfac4f33462d29fe (patch) | |
tree | 88f923c9c0be2e2a225a9b21716fd582de668b42 /contrib/nvi/ip_cl/ip_cl.c | |
download | FreeBSD-src-59cc89c2c2e686da3bdab2d5cfac4f33462d29fe.zip FreeBSD-src-59cc89c2c2e686da3bdab2d5cfac4f33462d29fe.tar.gz |
Import of nvi-1.79, minus a few bits that we dont need (eg: postscript
files, curses, db, regex etc that we already have). The other glue will
follow shortly.
Obtained from: Keith Bostic <bostic@bostic.com>
Diffstat (limited to 'contrib/nvi/ip_cl/ip_cl.c')
-rw-r--r-- | contrib/nvi/ip_cl/ip_cl.c | 742 |
1 files changed, 742 insertions, 0 deletions
diff --git a/contrib/nvi/ip_cl/ip_cl.c b/contrib/nvi/ip_cl/ip_cl.c new file mode 100644 index 0000000..5137b3f --- /dev/null +++ b/contrib/nvi/ip_cl/ip_cl.c @@ -0,0 +1,742 @@ +/*- + * Copyright (c) 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#ifndef lint +static const char sccsid[] = "@(#)ip_cl.c 8.4 (Berkeley) 10/13/96"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/queue.h> +#include <sys/select.h> + +#include <bitstring.h> +#include <ctype.h> +#include <curses.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "../common/common.h" +#include "../ip/ip.h" +#include "pathnames.h" + +size_t cols, rows; /* Screen columns, rows. */ +int die; /* Child died. */ +int i_fd, o_fd; /* Input/output fd's. */ +int resize; /* Window resized. */ + +void arg_format __P((int *, char **[], int, int)); +void attach __P((void)); +void ip_cur_end __P((void)); +void ip_cur_init __P((void)); +void ip_read __P((void)); +void ip_resize __P((void)); +int ip_send __P((char *, IP_BUF *)); +void ip_siginit __P((void)); +int ip_trans __P((char *, size_t, size_t *)); +void nomem __P((void)); +void onchld __P((int)); +void onintr __P((int)); +void onwinch __P((int)); +void trace __P((const char *, ...)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + fd_set fdset; + pid_t pid; + size_t blen, len, skip; + int ch, nr, rpipe[2], wpipe[2]; + char *bp; + + while ((ch = getopt(argc, argv, "D")) != EOF) + switch (ch) { + case 'D': + attach(); + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + /* + * Open the communications pipes. The pipes are named from our + * viewpoint, so we read from rpipe[0] and write to wpipe[1]. + * Vi reads from wpipe[0], and writes to rpipe[1]. + */ + if (pipe(rpipe) == -1 || pipe(wpipe) == -1) { + perror("ip_cl: pipe"); + exit (1); + } + i_fd = rpipe[0]; + o_fd = wpipe[1]; + + /* + * Format our arguments, adding a -I to the list. The first file + * descriptor to the -I argument is vi's input, and the second is + * vi's output. + */ + arg_format(&argc, &argv, wpipe[0], rpipe[1]); + + /* Run vi. */ + switch (pid = fork()) { + case -1: /* Error. */ + perror("ip_cl: fork"); + exit (1); + case 0: /* Vi. */ + execv(VI, argv); + perror("ip_cl: execv ../build/nvi"); + exit (1); + default: /* Ip_cl. */ + break; + } + + /* + * Allocate initial input buffer. + * XXX + * We don't dynamically resize, so there better not be any individual + * messages larger than this buffer. + */ + blen = 4 * 1024; + if ((bp = malloc(blen)) == NULL) + nomem(); + + /* Clear the file descriptor mask. */ + FD_ZERO(&fdset); + + /* Initialize signals. */ + ip_siginit(); + + /* Initialize the curses screen. */ + ip_cur_init(); + + /* The first thing vi wants is the screen size. */ + ip_resize(); + + /* Main loop. */ + for (len = 0;;) { + if (die) + break; + /* + * XXX + * Race #1: if there's an event coming from vi that requires + * that we know what size the screen is, and we take a resize + * signal, we'll differ from vi in the size of the screen for + * that event. Fixing this will requires information attached + * to message as to what set of state was in place when the + * message was sent. Not hard, but not worth doing now. + * + * Race #2: we cycle, handling resize events until there aren't + * any waiting. We then do a select. If the resize signal + * arrives after we exit the loop but before we enter select, + * we'll wait on the user to enter a keystroke, handle it and + * then handle the resize. + */ + while (resize) { + resize = 0; + ip_resize(); + ip_cur_end(); + ip_cur_init(); + } + + /* Wait until vi or the screen wants to talk. */ + FD_SET(i_fd, &fdset); + FD_SET(STDIN_FILENO, &fdset); + errno = 0; + switch (select(i_fd + 1, &fdset, NULL, NULL, NULL)) { + case 0: + abort(); /* Timeout. */ + /* NOTREACHED */ + case -1: + if (errno == EINTR) + continue; + perror("ip_cl: select"); + exit (1); + default: + break; + } + + /* Read waiting tty characters and send them to vi. */ + if (FD_ISSET(STDIN_FILENO, &fdset)) { + ip_read(); + continue; + } + + /* Read waiting vi messages and translate to curses calls. */ + switch (nr = read(i_fd, bp + len, blen - len)) { + case 0: + continue; + case -1: + perror("ip_cl: read"); + exit (1); + default: + break; + } + + /* Parse to data end or partial message. */ + for (len += nr, skip = 0; len > skip && + ip_trans(bp + skip, len - skip, &skip) == 1;); + + /* Copy any partial messages down in the buffer. */ + len -= skip; + if (len > 0) + memmove(bp, bp + skip, len); + } + + /* End the screen. */ + ip_cur_end(); + + exit (0); +} + +/* + * ip_read -- + * Read characters from the screen and send them to vi. + */ +void +ip_read() +{ + IP_BUF ipb; + int nr; + char bp[1024]; + + /* Read waiting tty characters. */ + switch (nr = read(STDIN_FILENO, bp, sizeof(bp))) { + case 0: + return; + case -1: + perror("ip_cl: read"); + exit (1); + default: + break; + } + + ipb.code = IPO_STRING; + ipb.len = nr; + ipb.str = bp; + ip_send("s", &ipb); +} + +/* + * ip_trans -- + * Translate vi messages into curses calls. + */ +int +ip_trans(bp, len, skipp) + char *bp; + size_t len, *skipp; +{ + IP_BUF ipb; + size_t cno, lno, nlen, oldy, oldx, spcnt; + int ch; + char *fmt, *p; + + switch (bp[0]) { + case IPO_ADDSTR: + case IPO_RENAME: + fmt = "s"; + break; + case IPO_BUSY: + fmt = "s1"; + break; + case IPO_ATTRIBUTE: + case IPO_MOVE: + fmt = "12"; + break; + case IPO_REWRITE: + fmt = "1"; + break; + default: + fmt = ""; + } + + nlen = IPO_CODE_LEN; + p = bp + IPO_CODE_LEN; + for (; *fmt != '\0'; ++fmt) + switch (*fmt) { + case '1': + nlen += IPO_INT_LEN; + if (len < nlen) + return (0); + memcpy(&ipb.val1, p, IPO_INT_LEN); + ipb.val1 = ntohl(ipb.val1); + p += IPO_INT_LEN; + break; + case '2': + nlen += IPO_INT_LEN; + if (len < nlen) + return (0); + memcpy(&ipb.val2, p, IPO_INT_LEN); + ipb.val2 = ntohl(ipb.val2); + p += IPO_INT_LEN; + break; + case 's': + nlen += IPO_INT_LEN; + if (len < nlen) + return (0); + memcpy(&ipb.len, p, IPO_INT_LEN); + ipb.len = ntohl(ipb.len); + p += IPO_INT_LEN; + nlen += ipb.len; + if (len < nlen) + return (0); + ipb.str = p; + p += ipb.len; + break; + } + *skipp += nlen; + + switch (bp[0]) { + case IPO_ADDSTR: +#ifdef TR + trace("addnstr {%.*s}\n", (int)ipb.len, ipb.str); +#endif + (void)addnstr(ipb.str, ipb.len); + break; + case IPO_ATTRIBUTE: + switch (ipb.val1) { + case SA_ALTERNATE: +#ifdef TR + trace("attr: alternate\n"); +#endif + /* + * XXX + * Nothing. + */ + break; + case SA_INVERSE: +#ifdef TR + trace("attr: inverse\n"); +#endif + if (ipb.val2) + (void)standout(); + else + (void)standend(); + break; + default: + abort(); + /* NOTREACHED */ + } + break; + case IPO_BELL: +#ifdef TR + trace("bell\n"); +#endif + (void)write(1, "\007", 1); /* '\a' */ + break; + case IPO_BUSY: +#ifdef TR + trace("busy {%.*s}\n", (int)ipb.len, ipb.str); +#endif + /* + * XXX + * Nothing... + * ip_busy(ipb.str, ipb.len); + */ + break; + case IPO_CLRTOEOL: +#ifdef TR + trace("clrtoeol\n"); +#endif + clrtoeol(); + break; + case IPO_DELETELN: +#ifdef TR + trace("deleteln\n"); +#endif + deleteln(); + break; + case IPO_INSERTLN: +#ifdef TR + trace("insertln\n"); +#endif + insertln(); + break; + case IPO_MOVE: +#ifdef TR + trace("move: %lu %lu\n", (u_long)ipb.val1, (u_long)ipb.val2); +#endif + (void)move(ipb.val1, ipb.val2); + break; + case IPO_REDRAW: +#ifdef TR + trace("redraw\n"); +#endif + clearok(curscr, 1); + refresh(); + break; + case IPO_REFRESH: +#ifdef TR + trace("refresh\n"); +#endif + refresh(); + break; + case IPO_RENAME: +#ifdef TR + trace("rename {%.*s}\n", (int)ipb.len, ipb.str); +#endif + /* + * XXX + * Nothing... + * ip_rename(ipb.str, ipb.len); + */ + break; + case IPO_REWRITE: +#ifdef TR + trace("rewrite {%lu}\n", (u_long)ipb.val1); +#endif + getyx(stdscr, oldy, oldx); + for (lno = ipb.val1, cno = spcnt = 0;;) { + (void)move(lno, cno); + ch = winch(stdscr); + if (isblank(ch)) + ++spcnt; + else { + (void)move(lno, cno - spcnt); + for (; spcnt > 0; --spcnt) + (void)addch(' '); + (void)addch(ch); + } + if (++cno >= cols) + break; + } + (void)move(oldy, oldx); + break; + default: + /* + * XXX: Protocol is out of sync? + */ + abort(); + } + + return (1); +} + +/* + * arg_format + */ +void +arg_format(argcp, argvp, i_fd, o_fd) + int *argcp, i_fd, o_fd; + char **argvp[]; +{ + char **largv, *iarg, *p; + + /* Get space for the argument array and the -I argument. */ + if ((iarg = malloc(64)) == NULL || + (largv = malloc((*argcp + 3) * sizeof(char *))) == NULL) { + perror("ip_cl"); + exit (1); + } + memcpy(largv + 2, *argvp, *argcp * sizeof(char *) + 1); + + /* Reset argv[0] to be the exec'd program. */ + if ((p = strrchr(VI, '/')) == NULL) + largv[0] = VI; + else + largv[0] = p + 1; + + /* Create the -I argument. */ + (void)sprintf(iarg, "-I%d%s%d", i_fd, ".", o_fd); + largv[1] = iarg; + + /* Reset the argument array. */ + *argvp = largv; +} + +/* + * ip_cur_init -- + * Initialize the curses screen. + */ +void +ip_cur_init() +{ + /* + * XXX + * This is 4BSD curses' specific -- if this is to be a real program + * we'll have to do all the stuff that we do in the cl directory to + * run with different curses variants. + */ + if (initscr() == ERR) { + perror("ip_cl: initscr"); + exit (1); + } + noecho(); + nonl(); + raw(); + idlok(stdscr, 1); +} + +/* + * ip_cur_end -- + * End the curses screen. + */ +void +ip_cur_end() +{ + (void)move(0, 0); + (void)deleteln(); + (void)move(rows - 1, 0); + (void)refresh(); + (void)endwin(); +} + +/* + * ip_siginit -- + * Initialize the signals. + */ +void +ip_siginit() +{ + /* We need to know if vi dies horribly. */ + (void)signal(SIGCHLD, onchld); + + /* We want to allow interruption at least for now. */ + (void)signal(SIGINT, onintr); + +#ifdef SIGWINCH + /* We need to know if the screen is resized. */ + (void)signal(SIGWINCH, onwinch); +#endif +} + +/* + * ip_resize -- + * Send the window size. + */ +void +ip_resize() +{ + struct winsize win; + IP_BUF ipb; + + if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) == -1) { + perror("ip_cl: TIOCGWINSZ"); + exit(1); + } + + if (rows == win.ws_row && cols == win.ws_col) + return; + + ipb.val1 = rows = win.ws_row; + ipb.val2 = cols = win.ws_col; + ipb.code = IPO_RESIZE; + ip_send("12", &ipb); +} + +/* + * ip_send -- + * Construct and send an IP buffer. + */ +int +ip_send(fmt, ipbp) + char *fmt; + IP_BUF *ipbp; +{ + static char *bp; + static size_t blen; + size_t off; + u_int32_t ilen; + int nlen, n, nw; + char *p; + + if (blen == 0 && (bp = malloc(blen = 512)) == NULL) + nomem(); + + p = bp; + nlen = 0; + *p++ = ipbp->code; + nlen += IPO_CODE_LEN; + + if (fmt != NULL) + for (; *fmt != '\0'; ++fmt) + switch (*fmt) { + case '1': /* Value 1. */ + ilen = htonl(ipbp->val1); + goto value; + case '2': /* Value 2. */ + ilen = htonl(ipbp->val2); +value: nlen += IPO_INT_LEN; + if (nlen >= blen) { + blen = blen * 2 + nlen; + off = p - bp; + if ((bp = realloc(bp, blen)) == NULL) + nomem(); + p = bp + off; + } + memmove(p, &ilen, IPO_INT_LEN); + p += IPO_INT_LEN; + break; + case 's': /* String. */ + ilen = ipbp->len; /* XXX: conversion. */ + ilen = htonl(ilen); + nlen += IPO_INT_LEN + ipbp->len; + if (nlen >= blen) { + blen = blen * 2 + nlen; + off = p - bp; + if ((bp = realloc(bp, blen)) == NULL) + nomem(); + p = bp + off; + } + memmove(p, &ilen, IPO_INT_LEN); + p += IPO_INT_LEN; + memmove(p, ipbp->str, ipbp->len); + p += ipbp->len; + break; + } +#ifdef TR + trace("WROTE: "); + for (n = p - bp, p = bp; n > 0; --n, ++p) + if (isprint(*p)) + (void)trace("%c", *p); + else + trace("<%x>", (u_char)*p); + trace("\n"); +#endif + + for (n = p - bp, p = bp; n > 0; n -= nw, p += nw) + if ((nw = write(o_fd, p, n)) < 0) { + perror("ip_cl: write"); + exit(1); + } + + return (0); +} + +void +nomem() +{ + perror("ip_cl"); + exit (1); +} + +/* + * onchld -- + * Handle SIGCHLD. + */ +void +onchld(signo) + int signo; +{ + die = 1; + +#ifdef TR + trace("SIGCHLD\n"); +#endif + + /* Interrupt select if it's running. */ + (void)kill(getpid(), SIGINT); +} + +/* + * onintr -- + * Handle SIGINT. + */ +void +onintr(signo) + int signo; +{ + /* + * If we receive an interrupt, we may have sent it ourselves. + * If not, die from the signal. + */ + if (die) + return; + (void)signal(SIGINT, SIG_DFL); + kill(getpid(), SIGINT); +} + +/* + * onwinch -- + * Handle SIGWINCH. + */ +void +onwinch(signo) + int signo; +{ + resize = 1; +} + +void +attach() +{ + int fd; + char ch; + + (void)printf("process %lu waiting, enter <CR> to continue: ", + (u_long)getpid()); + (void)fflush(stdout); + + if ((fd = open(_PATH_TTY, O_RDONLY, 0)) < 0) { + perror(_PATH_TTY); + exit (1);; + } + do { + if (read(fd, &ch, 1) != 1) { + (void)close(fd); + return; + } + } while (ch != '\n' && ch != '\r'); + (void)close(fd); +} + +#ifdef TR +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +/* + * TR -- + * debugging trace routine. + */ +void +#ifdef __STDC__ +trace(const char *fmt, ...) +#else +trace(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + static FILE *tfp; + va_list ap; + + if (tfp == NULL && (tfp = fopen(TR, "w")) == NULL) + tfp = stderr; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)vfprintf(tfp, fmt, ap); + va_end(ap); + + (void)fflush(tfp); +} +#endif + +void +usage() +{ + (void)fprintf(stderr, "usage: ip_cl [-D]\n"); + exit(1); +} |