view uip/vmh.c @ 0:bce86c4163a3

Initial revision
author kono
date Mon, 18 Apr 2005 23:46:02 +0900
parents
children a6481689f99c
line wrap: on
line source

/* vmh.c - visual front-end to mh */
#ifndef	lint
static char ident[] = "@(#)$Id$";
#endif	/* lint */
#if defined(SYS5) && !defined(linux) && !defined(TERMINFO)
/*
 * Define TERMINFO if you have it.
 * You get it automatically if you're running SYS5, and you don't get
 * it if you're not.  (If you're not SYS5, you probably have termcap.)
 * We distinguish TERMINFO from SYS5 because in this file SYS5 really
 * means "AT&T line discipline" (termio, not sgttyb), whereas terminfo
 * is quite a separate issue.
 */
#define	TERMINFO	1
#endif

/* TODO:
	Pass signals to client during execution

	Figure out a way for the user to say how big the Scan/Display
	windows should be.

	If curses ever gets fixed, then XYZ code can be removed
 */

#ifdef	UNISTD
#include <unistd.h>
#endif
#ifdef __osf__
#define _BSD
#endif
#ifdef NCURSES
#include <ncurses.h>
#else
#include <curses.h>
#endif /* NCURSES */
#if defined(__NCURSES_H) && !defined(TERMINFO)
#define TERMINFO
#endif /* __NCURSES_H */
#ifdef	ncr
#define	_SYS_REG_H		/* NCR redefines "ERR" in <sys/reg.h> */
#endif
#undef	OK			/* tricky */
#ifdef	TERMINFO
#include <term.h>	/* variables describing terminal capabilities */
#if defined(HAVE_TCGETATTR) && !defined(TCGETATTR)
#define TCGETATTR
#endif
#if defined(__NCURSES_H)
#if defined(TERMIOS) || defined(_USE_TERMIOS)
#ifndef SYS5
#define SYS5
#endif
#ifndef TCGETATTR
#define TCGETATTR
#endif
#endif /* TERMIOS */
#undef	OK			/* tricky */
#endif /* __NCURSES_H */
#endif	/* TERMINFO */
#include "../h/mh.h"
#include "../h/vmhsbr.h"
#include <ctype.h>
#include <errno.h>
#include <setjmp.h>
#include <signal.h>
#ifndef	sigmask
#define	sigmask(s)	(1 << ((s) - 1))
#endif	/* not sigmask */
#ifdef	ridge
#undef	SIGTSTP
#endif	/* ridge */
#if !defined(BSD42) && !defined(SVR4)
struct iovec {
    char   *iov_base;
    int     iov_len;
};
#else	/* BSD42 || SVR4 */
#include <sys/types.h>
#include <sys/uio.h>
#endif	/* BSD42 || SVR4 */
#ifdef LOCALE
#include	<locale.h>
#endif
#if defined(hpux) || defined(__osf__)
#include <termio.h>
#define	TCGETATTR		/* tcgetattr() */
#endif
#if !defined(__NCURSES_H) && (defined(BSD44) || defined(linux))
#define	USE_OLD_TTY
#define	_maxx	maxx		/* curses.h */
#define	_maxy	maxy
#define	_curx	curx		/* curses.h */
#define	_cury	cury
#ifndef __NetBSD__
void     __cputchar __P((int));
#endif
#undef	_putchar
#ifdef	BSD44
#define	_putchar	__cputchar
#else
#define	_putchar	(int (*)()) __cputchar
#endif
#include <sys/ioctl.h>		/* sgttyb */
#endif /* !__NCURSES_H && (BSD44 || linux) */

#define	ALARM	((unsigned int) 10)
#define	PAUSE	((unsigned int) 2)

#ifndef	abs
#define	abs(a)		((a) > 0 ? (a) : -(a))
#endif
#define	SMALLMOVE	1
#define	LARGEMOVE	10


#define	XYZ			/* XXX */

/*  */

static struct swit switches[] = {
#define	PRMPTSW	0
    "prompt string", 6,

#define	PROGSW	1
    "vmhproc program", 7,
#define	NPROGSW	2
    "novmhproc", 9,

#define	HELPSW	3
    "help", 4,

    NULL, 0
};

/*  */
					/* PEERS */
static int  PEERpid = NOTOK;

static  jmp_buf PEERctx;


					/* WINDOWS */
static char *myprompt = "(%s) ";

static  WINDOW *Scan;
static  WINDOW *Status;
static  WINDOW *Display;
static  WINDOW *Command;

#define	NWIN	3
static	int numwins;
WINDOW *windows[NWIN + 1];


					/* LINES */

struct line {
    int     l_no;
    char   *l_buf;
    struct line *l_prev;
    struct line *l_next;
};

static struct line *lhead = NULL;
static struct line *ltop = NULL;
static struct line *ltail = NULL;

static int did_less = 0;
static int smallmove = SMALLMOVE;
static int largemove = LARGEMOVE;


					/* TTYS */

static int  tty_ready = NOTOK;

static int  intrc;
#ifndef	SYS5
#define	ERASE	sg.sg_erase
#define	KILL	sg.sg_kill
static struct sgttyb    sg;

#define	EOFC	tc.t_eofc
#define	INTR	tc.t_intrc
static struct tchars    tc;
#else	/* SYS5 */
#define	ERASE	sg.c_cc[VERASE]
#define	KILL	sg.c_cc[VKILL]
#define	EOFC	sg.c_cc[VEOF]
#define	INTR	sg.c_cc[VINTR]
#ifdef __NCURSES_H
static TTY sg;
#else
#ifndef __osf__
static struct termio    sg;
#else
static struct termios   sg;
#endif /* __osf__ */
#endif /* __NCURSES_H */
#endif	/* SYS5 */

#ifndef	TIOCGLTC
#define	WERASC	('W' & 037)
#else	/* TIOCGLTC */
#ifndef SVR4
#define	WERASC	ltc.t_werasc
static struct ltchars ltc;
#else	/* SVR4 */
#define WERASC	sg.c_cc[VWERASE]
#undef TIOCGLTC		/* the define exists, but struct ltchars doesn't */
#endif
#endif	/* TIOCGLTC */


#if !defined(SYS5) && !defined(BSD44) && !defined(TERMINFO)
int	_putchar ();
#endif	/* not SYS5 */
#ifdef	SIGTSTP
char   *tgoto ();
#endif	/* SIGTSTP */


					/* SIGNALS */
static TYPESIG     ALRMser (), PIPEser (), SIGser ();
#ifdef	SIGTSTP
static TYPESIG	TSTPser ();
#endif	/* SIGTSTP */


					/* MISCELLANY */
extern int  errno;
#if !defined(BSD44) && !defined(__GNU_LIBRARY__)
extern int  sys_nerr;
extern char *sys_errlist[];
#endif

static void	adorn ();

static	vmh(), lreset(), linsert(), ladvance(), lretreat(), lgo();
static	TTYon(), TTYoff(), foreground();
static int	PEERinit(), pINI(), pLOOP(), pTTY(), pWIN(), WINinit();
static int	WINgetstr(), WINless(), WINputc(), TTYinit(), pWINaux();
/*  */

/* ARGSUSED */

main (argc, argv)
int     argc;
char   *argv[];
{
    int     vecp = 1,
	    nprog = 0;
    char   *cp,
            buffer[BUFSIZ],
          **ap,
          **argp,
           *arguments[MAXARGS],
           *vec[MAXARGS];

#ifdef LOCALE
	setlocale(LC_ALL, "");
#endif
#ifdef JAPAN
	ml_init();
#endif /* JAPAN */
    invo_name = r1bindex (argv[0], '/');
    if ((cp = m_find (invo_name)) != NULL) {
	ap = brkstring (cp = getcpy (cp), " ", "\n");
	ap = copyip (ap, arguments);
    }
    else
	ap = arguments;
    (void) copyip (argv + 1, ap);
    argp = arguments;

/*  */

    while (cp = *argp++)
	if (*cp == '-')
	    switch (smatch (++cp, switches)) {
		case AMBIGSW: 
		    ambigsw (cp, switches);
		    done (1);
		case UNKWNSW: 
		    vec[vecp++] = --cp;
		    continue;
		case HELPSW: 
		    (void) sprintf (buffer, "%s [switches for vmhproc]",
			    invo_name);
		    help (buffer, switches);
		    done (1);

		case PRMPTSW:
		    if (!(myprompt = *argp++) || *myprompt == '-')
			adios (NULLCP, "missing argument to %s", argp[-2]);
		    continue;

		case PROGSW: 
		    if (!(vmhproc = *argp++) || *vmhproc == '-')
			adios (NULLCP, "missing argument to %s", argp[-2]);
		    continue;
		case NPROGSW:
		    nprog++;
		    continue;
	    }
	else
	    vec[vecp++] = cp;

/*  */

    if (TTYinit (nprog) == NOTOK || WINinit (nprog) == NOTOK) {
	vec[vecp] = NULL;

	vec[0] = r1bindex (vmhproc, '/');
	execvp (vmhproc, vec);
	adios (vmhproc, "unable to exec");
    }
    TTYoff ();
    (void) PEERinit (vecp, vec);
    TTYon ();

    vmh ();

    done (0);
}

/*  */

static  vmh () {
    char    buffer[BUFSIZ];

    for (;;) {
	(void) pLOOP (RC_QRY, NULLCP);

	wmove (Command, 0, 0);
	wprintw (Command, myprompt, invo_name);
	wclrtoeol (Command);
	wrefresh (Command);

	switch (WINgetstr (Command, buffer)) {
	    case NOTOK: 
		break;

	    case OK:
		done (0);	/* NOTREACHED */

	    default: 
		if (*buffer)
		    (void) pLOOP (RC_CMD, buffer);
		break;
	}
    }
}

/*    PEERS */

static int  PEERinit (vecp, vec)
int	vecp;
char   *vec[];
{
    int	    pfd0[2],
            pfd1[2];
    char    buf1[BUFSIZ],
            buf2[BUFSIZ];

    if (pipe (pfd0) == NOTOK || pipe (pfd1) == NOTOK)
	adios ("pipe", "unable to");
#ifdef	hpux
    switch (PEERpid = fork ()) {
    /*
     * Calling vfork() and then another routine [like close()] before
     * an exec() messes up the stack frame, causing crib death.
     * Use fork() instead.
     */
#else	/* not hpux */
    switch (PEERpid = vfork ()) {
#endif	/* not hpux */
	case NOTOK: 
	    adios ("vfork", "unable to");/* NOTREACHED */

	case OK: 
	    (void) close (pfd0[0]);
	    (void) close (pfd1[1]);

	    vec[vecp++] = "-vmhread";
	    (void) sprintf (buf1, "%d", pfd1[0]);
	    vec[vecp++] = buf1;
	    vec[vecp++] = "-vmhwrite";
	    (void) sprintf (buf2, "%d", pfd0[1]);
	    vec[vecp++] = buf2;
	    vec[vecp] = NULL;

	    (void) signal (SIGINT, SIG_DFL);
	    (void) signal (SIGQUIT, SIG_DFL);

	    vec[0] = r1bindex (vmhproc, '/');
	    execvp (vmhproc, vec);
	    perror (vmhproc);
	    _exit (-1);		/* NOTREACHED */

	default: 
	    (void) close (pfd0[1]);
	    (void) close (pfd1[0]);

	    (void) rcinit (pfd0[0], pfd1[1]);
	    return pINI ();
    }
}

/*  */

static int  pINI () {
    register char  *bp;
    char    buffer[BUFSIZ];
    struct record   rcs;
    register struct record *rc = &rcs;
    register    WINDOW **w;

    initrc (rc);

    bp = buffer;
    (void) sprintf (bp, "%d %d", RC_VRSN, numwins);
    bp += strlen (bp);
    for (w = windows; *w; w++) {
#ifndef __NCURSES_H
#ifdef __NetBSD__
	(void) sprintf (bp, " %d", getmaxy(*w));
#else /* __NetBSD__ */
	(void) sprintf (bp, " %d", (*w) -> _maxy);
#endif /* __NetBSD__ */
#else /* __NCURSES_H */
	(void) sprintf (bp, " %d", (*w) -> _maxy + 1);
#endif /* __NCURSES_H */
	bp += strlen (bp);
    }

    switch (str2rc (RC_INI, buffer, rc)) {
	case RC_ACK: 
	    return OK;

	case RC_ERR: 
	    if (rc -> rc_len)
		adios (NULLCP, "%s", rc -> rc_data);
	    else
		adios (NULLCP, "pINI peer error");

	case RC_XXX: 
	    adios (NULLCP, "%s", rc -> rc_data);

	default:
	    adios (NULLCP, "pINI protocol screw-up");
    }
/* NOTREACHED */
}

/*  */

static int  pLOOP (code, str)
char	code,
       *str;
{
    int	    i;
    struct record   rcs;
    register struct record *rc = &rcs;

    initrc (rc);

    (void) str2peer (code, str);
    for (;;)
	switch (peer2rc (rc)) {
	    case RC_TTY:
		if (pTTY (rc) == NOTOK)
		    return NOTOK;
		break;

	    case RC_WIN:
		if (sscanf (rc -> rc_data, "%d", &i) != 1
			|| i <= 0
			|| i > numwins) {
		    (void) fmt2peer (RC_ERR, "no such window \"%s\"",
				rc -> rc_data);
		    return NOTOK;
		}
		if (pWIN (windows[i - 1]) == NOTOK)
		    return NOTOK;
		break;

	    case RC_EOF:
		return OK;

	    case RC_ERR:
		if (rc -> rc_len)
		    adorn (NULLCP, "%s", rc -> rc_data);
		else
		    adorn (NULLCP, "pLOOP(%s) peer error",
			    code == RC_QRY ? "QRY" : "CMD");
		return NOTOK;

	    case RC_FIN:
		if (rc -> rc_len)
		    adorn (NULLCP, "%s", rc -> rc_data);
		(void) rcdone ();
		i = pidwait (PEERpid, OK);
		PEERpid = NOTOK;
		done (i);

	    case RC_XXX: 
		adios (NULLCP, "%s", rc -> rc_data);

	    default:
		adios (NULLCP, "pLOOP(%s) protocol screw-up",
			code == RC_QRY ? "QRY" : "CMD");
	}
}

/*  */

static int  pTTY (r)
register struct record *r;
{
    TYPESIG (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
    struct record   rcs;
    register struct record *rc = &rcs;

    initrc (rc);

    TTYoff ();

    hstat = signal (SIGHUP, SIG_IGN);
    istat = signal (SIGINT, SIG_IGN);
    qstat = signal (SIGQUIT, SIG_IGN);
    tstat = signal (SIGTERM, SIG_IGN);

    (void) rc2rc (RC_ACK, 0, NULLCP, rc);

    (void) signal (SIGHUP, hstat);
    (void) signal (SIGINT, istat);
    (void) signal (SIGQUIT, qstat);
    (void) signal (SIGTERM, tstat);

    TTYon ();

    if (r -> rc_len && strcmp (r -> rc_data, "FAST") == 0)
	goto no_refresh;

#ifdef	SIGTSTP
    (void) signal (SIGTSTP, SIG_IGN);
#endif	/* SIGTSTP */
#ifndef	TERMINFO
    if (SO)
	tputs (SO, 0, _putchar);
#else	/* TERMINFO */
    putp(enter_standout_mode);
#endif	/* TERMINFO */
    fprintf (stdout, "Type any key to continue... ");
    (void) fflush (stdout);
#ifndef	TERMINFO
    if (SE)
	tputs (SE, 0, _putchar);
#else	/* TERMINFO */
    putp(exit_standout_mode);
#endif	/* TERMINFO */
    (void) getc (stdin);
#ifdef	SIGTSTP
    (void) signal (SIGTSTP, TSTPser);
#endif	/* SIGTSTP */

    wrefresh (curscr);

no_refresh: ;
    switch (rc -> rc_type) {
	case RC_EOF: 
	    (void) rc2peer (RC_ACK, 0, NULLCP);
	    return OK;

	case RC_ERR: 
	    if (rc -> rc_len)
		adorn (NULLCP, "%s", rc -> rc_data);
	    else
		adorn (NULLCP, "pTTY peer error");
	    return NOTOK;

	case RC_XXX: 
	    adios (NULLCP, "%s", rc -> rc_data);

	default:
	    adios (NULLCP, "pTTY protocol screw-up");
    }
/* NOTREACHED */
}

/*  */

static int  pWIN (w)
register WINDOW *w;
{
    int     i;

    did_less = 0;
    if ((i = pWINaux (w)) == OK && did_less)
	(void) WINless (w, 1);

    lreset ();

    return i;
}

/*  */

static int  pWINaux (w)
register WINDOW *w;
{
    register int    n;
    int	    eol;
    register char   c,
                   *bp;
    struct record   rcs;
    register struct record *rc = &rcs;
#ifdef JAPAN
    char   *cp, *ep, *tmpbak = NULLCP;
    int kanji1st; /* kanji 1st byte? */
#endif /* JAPAN */

    initrc (rc);

    werase (w);
    wmove (w, 0, 0);
#ifdef	XYZ
    if (w == Status)
	wstandout (w);
#endif	/* XYZ */

    for (eol = 0;;)
	switch (rc2rc (RC_ACK, 0, NULLCP, rc)) {
	    case RC_DATA: 
		if (eol && WINputc (w, '\n') == ERR && WINless (w, 0))
		    goto flush;
#ifdef JAPAN
		ep = add(rc -> rc_data, tmpbak);
		if ((cp = rindex(ep, '\n'))) {
		    strcpy(rc -> rc_data, ++cp);
		    *cp = '\0';
		    tmpbak = rc -> rc_data;
		    rc -> rc_data = ep;
		} else {
		    rc -> rc_data[0] = '\0';
		    tmpbak = ep;
		}
		(void) ml_conv(rc -> rc_data);
		rc -> rc_len = strlen(rc -> rc_data);
		kanji1st = 0;
#endif /* JAPAN */
		for (bp = rc -> rc_data, n = rc -> rc_len; n-- > 0; ) {
#ifdef JAPAN
		    if ((unsigned char) (c = *bp) > 0xa0
			&& (unsigned char) c < 0xff) /* EUC */
			kanji1st = kanji1st ? 0 : 1;
#endif /* JAPAN */
		    if ((c = *bp++) == '\n')
		        linsert (w);
#ifndef __NCURSES_H
#ifdef __NetBSD__
		    else if (getcurx(w) == getmaxx(w) - 2 && w == Display) {
#else /* __NetBSD__ */
		    else if (w -> _curx == w -> _maxx - 2 && w == Display) {
#endif /* __NetBSD__ */
#else /* __NCURSES_H */
		    else if (w -> _curx == w -> _maxx - 1 && w == Display) {
#endif /* __NCURSES_H */
			linsert(w);
#ifdef JAPAN
			if (!kanji1st
			    && (c & 0x7f) > 0x20 && (c & 0x7f) < 0x7f) {
#else /* JAPAN */
			if (c > 0x20 && c < 0x7f) {
#endif /* JAPAN */
			    int i;
#ifdef __NetBSD__
			    for (i = strlen(ltail->l_buf); i < getcurx(w); i++)
				ltail -> l_buf[i] = ' ';
			    ltail -> l_buf[getcurx(w)] = c;
			    ltail -> l_buf[getcurx(w)] = '\0';
#else /* __NetBSD__ */
			    for (i = strlen(ltail->l_buf); i < w->_curx; i++)
				ltail -> l_buf[i] = ' ';
			    ltail -> l_buf[w -> _curx] = c;
			    ltail -> l_buf[w -> _curx + 1] = '\0';
#endif /* __NetBSD__ */
			} else {
#ifdef JAPAN
			    kanji1st = 0;
#endif /* JAPAN */
			    c = '\n';
			    bp--;
			    n++;
			}
		    }
		    if (WINputc (w, c) == ERR
#ifndef __NCURSES_H
#ifdef __NetBSD__
			|| (getcurx(w) >= getmaxx(w) - 1 && w == Display
#else /* __NetBSD__ */
			|| (w -> _curx >= w -> _maxx - 1 && w == Display
#endif /* __NetBSD__ */
#else /* __NCURSES_H */
		        || (w -> _curx >= w -> _maxx && w == Display
#endif /* __NCURSES_H */
			    && WINputc (w, '\n') == ERR))
			if (n == 0 && c == '\n')
			    eol++;
			else
			    if (WINless (w, 0)) {
flush: ;
				(void) fmt2peer (RC_ERR, "flush window");
#ifdef	XYZ			/* should NEVER happen... */
				if (w == Status)
				    wstandend (w);
#endif	/* XYZ */
				wrefresh (w);
				return NOTOK;
			    }
		}
		break;

	    case RC_EOF: 
		(void) rc2peer (RC_ACK, 0, NULLCP);
#ifdef	XYZ
		if (w == Status)
		    wstandend (w);
#endif	/* XYZ */
		wrefresh (w);
		return OK;

	    case RC_ERR: 
		if (rc -> rc_len)
		    adorn (NULLCP, "%s", rc -> rc_data);
		else
		    adorn (NULLCP, "pWIN peer error");
		return NOTOK;

	    case RC_XXX: 
		adios (NULLCP, "%s", rc -> rc_data);

	    default:
		adios (NULLCP, "pWIN protocol screw-up");
	}
/* NOTREACHED */
}

/*  */

static int  pFIN () {
    int     status;

    if (PEERpid <= OK)
	return OK;

    (void) rc2peer (RC_FIN, 0, NULLCP);
    (void) rcdone ();

    switch (setjmp (PEERctx)) {
	case OK: 
	    (void) signal (SIGALRM, ALRMser);
	    (void) alarm (ALARM);

	    status = pidwait (PEERpid, OK);

	    (void) alarm (0);
	    break;

	default: 
	    (void) kill (PEERpid, SIGKILL);
	    status = NOTOK;
	    break;
    }
    PEERpid = NOTOK;

    return status;
}

/*    WINDOWS */

static int  WINinit (nprog) {
    register int    nlines,	/* not "lines" because terminfo uses that */
                    top,
                    bottom;

    foreground ();
    if (initscr () == (WINDOW *) ERR)
	if (nprog)
	    return NOTOK;
	else
	    adios (NULLCP, "could not initialize terminal");
#ifdef	SIGTSTP
    (void) signal (SIGTSTP, SIG_DFL);
#endif	/* SIGTSTP */
    sideground ();

#ifndef	TERMINFO
    if (CM == NULL)
#else	/* TERMINFO */
    if (cursor_address == NULL)	/* assume mtr wanted "cm", not "CM" */
#endif	/* TERMINFO */
	if (nprog)
	    return NOTOK;
	else
	    adios (NULLCP,
		    "sorry, your terminal isn't powerful enough to run %s",
		    invo_name);

#ifndef	TERMINFO
    if (tgetflag ("xt") || tgetnum ("sg") > 0)
	SO = SE = US = UE = NULL;
#else	/* TERMINFO */
/*
 * If termcap mapped directly to terminfo, we'd use the following:
 *  if (teleray_glitch || magic_cookie_glitch > 0)
 *	enter_standout_mode = exit_standout_mode =
 *	enter_underline_mode = exit_underline_mode = NULL;
 * But terminfo does the right thing so we don't have to resort to that.
 */
#endif	/* TERMINFO */

    if ((nlines = LINES - 1) < 11)
	adios (NULLCP, "screen too small");
    if ((top = nlines / 3 + 1) > LINES / 4 + 2)
	top--;
    bottom = nlines - top - 2;

    numwins = 0;
    Scan = windows[numwins++] = newwin (top, COLS, 0, 0);
    Status = windows[numwins++] = newwin (1, COLS, top, 0);
#ifndef	XYZ
    wstandout (Status);
#endif	/* XYZ */
    Display = windows[numwins++] = newwin (bottom, COLS, top + 1, 0);
    Command = newwin (1, COLS - 1, top + 1 + bottom, 0);
    windows[numwins] = NULL;

#ifndef __NCURSES_H
#ifdef __NetBSD__
    largemove = getmaxy(Display) / 2 + 2;
#else /* __NetBSD__ */
    largemove = Display -> _maxy / 2 + 2;
#endif /* __NetBSD__ */
#else /* __NCURSES_H */
    largemove = (Display -> _maxy + 1) / 2 + 2;
#endif /* __NCURSES_H */
    return OK;
}

/*  */

static int WINgetstr (w, buffer)
register WINDOW *w;
char   *buffer;
{
    register int    c;
    register char  *bp;

    bp = buffer;
    *bp = 0;

    for (;;) {
	switch (c = wgetch (w) & 0xff) {
	    case ERR: 
		adios (NULLCP, "wgetch lost");

	    case '\f':
		wrefresh (curscr);
		break;

	    case '\r': 
	    case '\n': 
		*bp = 0;
		if (bp > buffer) {
		    leaveok (curscr, FALSE);
#ifdef __NetBSD__
		    wmove (w, 0, getcurx(w) - (bp - buffer));
#else /* __NetBSD__ */
		    wmove (w, 0, w -> _curx - (bp - buffer));
#endif /* __NetBSD__ */
		    wrefresh (w);
		    leaveok (curscr, TRUE);
		}
		return DONE;

	    default: 
		if (c == intrc) {
		    wprintw (w, " ");
		    wstandout (w);
		    wprintw (w, "Interrupt");
		    wstandend (w);
		    wrefresh (w);
		    *buffer = 0;
		    return NOTOK;
		}
		if (c == EOFC) {
		    if (bp <= buffer)
			return OK;
		    break;
		}
		if (c == ERASE) {
		    if (bp <= buffer)
			continue;
#ifdef __NetBSD__
		    bp--;
		    wmove(w, getcury(w), getcurx(w) - 1);
		    wrefresh(w);
#else /* __NetBSD__ */
		    bp--, w -> _curx--;
#endif /* __NetBSD__ */
		    wclrtoeol (w);
		    break;
		}
		if (c == KILL) {
		    if (bp <= buffer)
			continue;
#ifdef __NetBSD__
		    wmove(w, getcury(w), getcurx(w) - (bp - buffer));
		    wrefresh(w);
#else /* __NetBSD__ */
		    w -> _curx -= bp - buffer;
#endif /* __NetBSD__ */
		    bp = buffer;
		    wclrtoeol (w);
		    break;
		}
		if (c == WERASC) {
		    if (bp <= buffer)
			continue;
		    do {
#ifdef __NetBSD__
			bp--;
			wmove(w, getcury(w), getcurx(w) - 1);
#else /* __NetBSD__ */
			bp--, w -> _curx--;
#endif /* __NetBSD__ */
		    } while (isspace (*bp) && bp > buffer);

		    if (bp > buffer) {
			do {
#ifdef __NetBSD__
			    bp--;
			    wmove(w, getcury(w), getcurx(w) - 1);
#else /* __NetBSD__ */
			    bp--, w -> _curx--;
#endif /* __NetBSD__ */
			} while (!isspace (*bp) && bp > buffer);
			if (isspace (*bp))
#ifdef __NetBSD__
			    {
				bp++;
				wmove(w, getcury(w), getcurx(w) + 1);
			    }
#else /* __NetBSD__ */
			    bp++, w -> _curx++;
#endif /* __NetBSD__ */
		    }
#ifdef __NetBSD__
		    wrefresh (w);
#endif /* __NetBSD__ */
		    wclrtoeol (w);
		    break;
		}
		
		if ((c >= ' ' && c < '\177') || (c >= 0xa1 && c <= 0xfe))
		    (void) waddch (w, *bp++ = c);
		break;
	}

	wrefresh (w);
    }
}

/*  */

static int  WINwritev (w, iov, n)
register WINDOW *w;
register struct iovec   *iov;
register int     n;
{
    register int    i;

    werase (w);
    wmove (w, 0, 0);
    for (i = 0; i < n; i++, iov++)
	wprintw (w, "%*.*s", iov -> iov_len, iov -> iov_len, iov -> iov_base);
    wrefresh (w);

    sleep (PAUSE);

    return OK;
}

/*  */

static struct {
    char   *h_msg;
    int    *h_val;
}               hlpmsg[] = {
                    "		forward		backwards", NULL,
                    "		-------		---------", NULL,
                    "next screen	SPACE", NULL,
                    "next %d line%s	RETURN		y", &smallmove,
                    "next %d line%s	EOT		u", &largemove,
                    "go		g		G", NULL,
                    "", NULL,
                    "refresh		CTRL-L", NULL,
                    "quit		q", NULL,

                    NULL, NULL
};

/*  */

static int  WINless (w, fin)
register WINDOW *w;
int	fin;
{
    register int    c,
                    i,
                    n;
    int     nfresh,
#ifdef	notdef
	    nlatch,
#endif	/* notdef */
            nwait;
    char   *cp;
    register struct line   *lbottom;

    did_less++;

    cp = NULL;
#ifdef	notdef
    if (fin)
	ltop = NULL;
#endif	/* notdef */
    lbottom = NULL;
    nfresh = 1;
    nwait = 0;
    wrefresh (w);

    for (;;) {
	if (nfresh || nwait) {
	    nfresh = 0;
#ifdef	notdef
	    nlatch = 1;

once_only: ;
#endif	/* notdef */
	    werase (w);
	    wmove (w, 0, 0);

	    if (ltop == NULL)
		if (fin) {
#ifndef __NCURSES_H
#ifdef __NetBSD__
		    (void) lgo (ltail -> l_no - getmaxy(w) + 1);
#else /* __NetBSD__ */
		    (void) lgo (ltail -> l_no - w -> _maxy + 1);
#endif /* __NetBSD__ */
#else /* __NCURSES_H */
		    (void) lgo (ltail -> l_no - w -> _maxy + 2);
#endif /* __NCURSES_H */
		    if (ltop == NULL)
			ltop = lhead;
		}
		else
		    ltop = lbottom && lbottom -> l_prev ? lbottom -> l_prev
			    : lbottom;

	    for (lbottom = ltop; lbottom; lbottom = lbottom -> l_next)
		if (waddstr (w, lbottom -> l_buf) == ERR
			|| waddch (w, '\n') == ERR)
		    break;
	    if (lbottom == NULL)
		if (fin) {
#ifdef	notdef
#ifndef __NCURSES_H
#ifdef __NetBSD__
		    if (nlatch && (ltail -> l_no >= getmaxy(w))) {
			(void) lgo (ltail -> l_no - getmaxy(w) + 1);
#else /* __NetBSD__ */
		    if (nlatch && (ltail -> l_no >= w -> _maxy)) {
			(void) lgo (ltail -> l_no - w -> _maxy + 1);
#endif /* __NetBSD__ */
#else /* __NCURSES_H */
		    if (nlatch && (ltail -> l_no > w -> _maxy)) {
			(void) lgo (ltail -> l_no - w -> _maxy + 2);
#endif /* __NCURSES_H */
			nlatch = 0;
			goto once_only;
		    }
#endif	/* notdef */
		    lbottom = ltail;
		    while (waddstr (w, "~\n") != ERR)
			continue;
		}
		else {
		    wrefresh (w);
		    return 0;
		}

	    if (!nwait)
		wrefresh (w);
	}

	wmove (Command, 0, 0);
	if (cp) {
	    wstandout (Command);
	    wprintw (Command, "%s", cp);
	    wstandend (Command);
	    cp = NULL;
	}
	else
	    wprintw (Command, fin ? "top:%d bot:%d end:%d" : "top:%d bot:%d",
		    ltop -> l_no, lbottom -> l_no, ltail -> l_no);
	wprintw (Command, ">> ");
	wclrtoeol (Command);
	wrefresh (Command);

	c = toascii (wgetch (Command));

	werase (Command);
	wrefresh (Command);

	if (nwait) {
	    nwait = 0;
	    wrefresh (w);
	}

	n = 0;
again: 	;
	switch (c) {
	    case ' ': 
		ltop = lbottom -> l_next;
		nfresh++;
		break;

	    case '\r': 
	    case '\n': 
	    case 'e': 
	    case 'j': 
		if (n)
		    smallmove = n;
		if (ladvance (smallmove))
		    nfresh++;
		break;

	    case 'y': 
	    case 'k': 
		if (n)
		    smallmove = n;
		if (lretreat (smallmove))
		    nfresh++;
		break;

	    case 'd': 
	eof: 	;
		if (n)
		    largemove = n;
		if (ladvance (largemove))
		    nfresh++;
		break;

	    case 'u': 
		if (n)
		    largemove = n;
		if (lretreat (largemove))
		    nfresh++;
		break;

	    case 'g': 
		if (lgo (n ? n : 1))
		    nfresh++;
		break;

	    case 'G': 
#ifndef __NCURSES_H
#ifdef __NetBSD__
		if (lgo (n ? n : ltail -> l_no - getmaxy(w) + 1))
#else /* __NetBSD__ */
		if (lgo (n ? n : ltail -> l_no - w -> _maxy + 1))
#endif /* __NetBSD__ */
#else /* __NCURSES_H */
		if (lgo (n ? n : ltail -> l_no - w -> _maxy + 2))
#endif /* __NCURSES_H */
		    nfresh++;
		break;

	    case '\f': 
	    case 'r': 
		wrefresh (curscr);
		break;

	    case 'h': 
	    case '?': 
		werase (w);
		wmove (w, 0, 0);
		for (i = 0; hlpmsg[i].h_msg; i++) {
		    if (hlpmsg[i].h_val)
			wprintw (w, hlpmsg[i].h_msg, *hlpmsg[i].h_val,
				*hlpmsg[i].h_val != 1 ? "s" : "");
		    else
			(void) waddstr (w, hlpmsg[i].h_msg);
		    (void) waddch (w, '\n');
		}
		wrefresh (w);
		nwait++;
		break;

	    case 'q': 
		return 1;

	    default: 
		if (c == EOFC)
		    goto eof;

		if (isdigit (c)) {
		    wmove (Command, 0, 0);
		    i = 0;
		    while (isdigit (c)) {
			wprintw (Command, "%c", c);
			wrefresh (Command);
			i = i * 10 + c - '0';
			c = toascii (wgetch (Command));
		    }
		    werase (Command);
		    wrefresh (Command);

		    if (i > 0) {
			n = i;
			goto again;
		    }
		    cp = "bad number";
		}
		else
		    cp = "not understood";
		break;
	}
    }
}

/*  */

static int  WINputc (w, c)
register WINDOW *w;
register unsigned char c;
{
    register int    x,
                    y;

    switch (c) {
	default: 
	    if (!isascii (c)
		&& !(c >= 0xa1 && c <= 0xfe) /* pass EUC or ISO-8859-x */
		) {
		if (WINputc (w, 'M') == ERR || WINputc (w, '-') == ERR)
		    return ERR;
		c = toascii (c);
	    }
	    else
		if (c < ' ' || c == '\177') {
		    if (WINputc (w, '^') == ERR)
			return ERR;
		    c ^= 0100;
		}
	    break;

	case '\t': 
	case '\n': 
	    break;
    }

    if (w != Scan)
	return waddch (w, c);

#ifndef __NCURSES_H
#ifdef __NetBSD__
    if ((x = getcurx(w)) < 0 || x >= getmaxx(w)
	    || (y = getcury(w)) < 0 || y >= getmaxy(w))
#else /* __NetBSD__ */
    if ((x = w -> _curx) < 0 || x >= w -> _maxx
	    || (y = w -> _cury) < 0 || y >= w -> _maxy)
#endif /* __NetBSD__ */
#else /* __NCURSES_H */
    if ((x = w -> _curx) < 0 || x > w -> _maxx
	    || (y = w -> _cury) < 0 || y > w -> _maxy)
#endif /* __NCURSES_H */
	return DONE;

    switch (c) {
	case '\t': 
	    for (x = 8 - (x & 0x07); x > 0; x--)
		if (WINputc (w, ' ') == ERR)
		    return ERR;
	    break;

	case '\n': 
#ifndef __NCURSES_H
#ifdef __NetBSD__
	    if (++y < getmaxy(w)) 
#else /* __NetBSD__ */
	    if (++y < w -> _maxy) 
#endif /* __NetBSD__ */
#else /* __NCURSES_H */
	    if (++y <= w -> _maxy) 
#endif /* __NCURSES_H */
		(void) waddch (w, c);
	    else
		wclrtoeol (w);
	    break;

	default: 
#ifndef __NCURSES_H
#ifdef __NetBSD__
	    if (++x < getmaxx(w)) 
#else /* __NetBSD__ */
	    if (++x < w -> _maxx) 
#endif /* __NetBSD__ */
#else /* __NCURSES_H */
	    if (++x <= w -> _maxx) 
#endif /* __NCURSES_H */
		(void) waddch (w, c);
	    break;
    }

    return DONE;
}

/*    LINES */

static  lreset () {
    register struct line   *lp,
                           *mp;

    for (lp = lhead; lp; lp = mp) {
	mp = lp -> l_next;
	free (lp -> l_buf);
	free ((char *) lp);
    }
    lhead = ltop = ltail = NULL;
}


static	linsert (w)
WINDOW *w;
{
    register char  *cp;
    register struct line   *lp;

    if ((lp = (struct line  *) calloc ((unsigned) 1, sizeof *lp)) == NULL)
	adios (NULLCP, "unable to allocate line storage");

    lp -> l_no = (ltail ? ltail -> l_no : 0) + 1;
    /*
     * "chtype" is not always "char".  We must not do getcpy() simply.
     */
    /* lp -> l_buf = getcpy (w -> _y[w -> _cury]); */
#ifndef __NCURSES_H
#ifdef __NetBSD__
    {
	int i, cur;
	if ((lp -> l_buf = (char *) malloc(getmaxx(w) + 1)) == NULL)
	    adios (NULLCP, "unable to allocate storage");
	cur = getcurx(w);
	for (i = 0; i < getmaxx(w); i++) {
#ifdef getmaxx
	    /* maybe older than NetBSD-1.5 */
	    lp -> l_buf[i] = w -> lines[getcury(w)] -> line[i].ch;
#else
	    wmove(w, getcury(w), i);
	    lp -> l_buf[i] = winch(w); /* 8bit ?? */
#endif
	}
	lp -> l_buf[getmaxx(w)] = '\0';
	wmove(w, getcury(w), cur);
    }
#else /* __NetBSD__ */
    {
	int i;
	if ((lp -> l_buf = (char *) malloc(w -> _maxx + 1)) == NULL)
	    adios (NULLCP, "unable to allocate storage");
	for (i = 0; i < w -> _maxx; i++)
#if !defined(BSD44) && !defined(__386BSD__) && !defined(linux)
	    lp -> l_buf[i] = (char) w -> _y[w -> _cury][i];
#else
	    lp -> l_buf[i] = w -> lines[w -> _cury] -> line[i].ch;
#endif
	lp -> l_buf[w -> _maxx] = '\0';
    }
#endif /* __NetBSD__ */
#else /* __NCURSES_H */
    {
	int i;
	if ((lp -> l_buf = (char *) malloc(w -> _maxx + 2)) == NULL)
	    adios (NULLCP, "unable to allocate storage");
	for (i = 0; i <= w -> _maxx; i++)
	    lp -> l_buf[i] = (char) w -> _line[w -> _cury].text[i];
	lp -> l_buf[w -> _maxx + 1] = '\0';
    }
#endif /* __NCURSES_H */
    for (cp = lp -> l_buf + strlen (lp -> l_buf) - 1; cp >= lp -> l_buf; cp--)
	if (isspace (*cp))
	    *cp = 0;
	else
	    break;

    if (lhead == NULL)
	lhead = lp;
    if (ltop == NULL)
	ltop = lp;
    if (ltail)
	ltail -> l_next = lp;
    lp -> l_prev = ltail;
    ltail = lp;
}

/*  */

static int  ladvance (n)
int	n;
{
    register int    i;
    register struct line   *lp;

    for (i = 0, lp = ltop; i < n && lp; i++, lp = lp -> l_next)
	continue;

    if (ltop == lp)
	return 0;

    ltop = lp;
    return 1;
}


static int  lretreat (n)
int	n;
{
    register int    i;
    register struct line   *lp;

    for (i = 0, lp = ltop; i < n && lp; i++, lp = lp -> l_prev)
	if (!lp -> l_prev)
	    break;

    if (ltop == lp)
	return 0;

    ltop = lp;
    return 1;
}

/*  */

static int  lgo (n)
int	n;
{
    register int    i,
                    j;
    register struct line   *lp;

    if ((i = n - (lp = lhead) -> l_no)
	    > (j = abs (n - (ltop ? ltop : ltail) -> l_no)))
	i = j, lp = ltop ? ltop : ltail;
    if (i > (j = abs (ltail -> l_no - n)))
	i = j, lp = ltail;

    if (n >= lp -> l_no) {
	for (; lp; lp = lp -> l_next)
	    if (lp -> l_no == n)
		break;
    }
    else {
	for (; lp; lp = lp -> l_prev)
	    if (lp -> l_no == n)
		break;
	if (!lp)
	    lp = lhead;
    }

    if (ltop == lp)
	return 0;

    ltop = lp;
    return 1;
}

/*    TTYS */

static int  TTYinit (nprog) {
    if (!isatty (fileno (stdin)) || !isatty (fileno (stdout)))
	if (nprog)
	    return NOTOK;
	else
	    adios (NULLCP, "not a tty");

    foreground ();
#ifndef	SYS5
    if (ioctl (fileno (stdin), TIOCGETP, (char *) &sg) == NOTOK)
	adios ("failed", "ioctl TIOCGETP");
    if (ioctl (fileno (stdin), TIOCGETC, (char *) &tc) == NOTOK)
	adios ("failed", "ioctl TIOCGETC");
#else	/* SYS5 */
#ifdef	TCGETATTR
    if( tcgetattr( fileno(stdin), &sg) == NOTOK)
	adios( "failed", "tcgetattr");
#else
    if (ioctl (fileno (stdin), TCGETA, &sg) == NOTOK)
	adios ("failed", "ioctl TCGETA");
#endif
#endif	/* SYS5 */
#ifdef	TIOCGLTC
    if (ioctl (fileno (stdin), TIOCGLTC, (char *) &ltc) == NOTOK)
	adios ("failed", "ioctl TIOCGLTC");
#endif	/* TIOCGLTC */
    intrc = INTR;
    sideground ();

    tty_ready = OK;

    (void) signal (SIGPIPE, PIPEser);

    return OK;
}

/*  */

static	TTYon () {
    if (tty_ready == DONE)
	return;

    INTR = NOTOK;
#ifndef	SYS5
    (void) ioctl (fileno (stdin), TIOCSETC, (char *) &tc);
#else	/* SYS5 */
#if defined(TCGETATTR) && !defined(TCSETA) && defined(TCSANOW)
    (void) tcsetattr (fileno (stdin), TCSANOW, &sg);
#else
    (void) ioctl (fileno (stdin), TCSETA, &sg);
#endif
#endif	/* SYS5 */

    (void) crmode ();
    (void) noecho ();
    (void) nonl ();
    scrollok (curscr, FALSE);

    discard (stdin);

    tty_ready = DONE;

    (void) signal (SIGHUP, SIGser);
    (void) signal (SIGINT, SIGser);
    (void) signal (SIGQUIT, SIGser);
#ifdef	SIGTSTP
    (void) signal (SIGTSTP, TSTPser);
#endif	/* SIGTSTP */
}

/*  */

static	TTYoff () {
    if (tty_ready == NOTOK)
	return;

    INTR = intrc;
#ifndef	SYS5
    (void) ioctl (fileno (stdin), TIOCSETC, (char *) &tc);
#else	/* SYS5 */
#if defined(TCGETATTR) && !defined(TCSETA) && defined(TCSANOW)
    (void) tcsetattr (fileno (stdin), TCSANOW, &sg);
#else
    (void) ioctl (fileno (stdin), TCSETA, &sg);
#endif
#endif	/* SYS5 */

    leaveok (curscr, TRUE);
    mvcur (0, COLS - 1, LINES - 1, 0);
    endwin ();
    if (tty_ready == DONE) {
#ifndef	TERMINFO
	if (CE)
	    tputs (CE, 0, _putchar);
	else
#else	/* TERMINFO */
	putp(clr_eol);
#endif	/* TERMINFO */
	    fprintf (stdout, "\r\n");
    }
    (void) fflush (stdout);

    tty_ready = NOTOK;

    (void) signal (SIGHUP, SIG_DFL);
    (void) signal (SIGINT, SIG_DFL);
    (void) signal (SIGQUIT, SIG_DFL);
#ifdef	SIGTSTP
    (void) signal (SIGTSTP, SIG_DFL);
#endif	/* SIGTSTP */
}

/*  */

static  foreground () {
#ifdef	TIOCGPGRP
    int     pgrp,
            tpgrp;
    TYPESIG     (*tstat) ();

    if ((pgrp = getpgrp (/*0*/)) == NOTOK)
	adios ("process group", "unable to determine");
    for (;;) {
	if (ioctl (fileno (stdin), TIOCGPGRP, (char *) &tpgrp) == NOTOK)
	    adios ("tty's process group", "unable to determine");
	if (pgrp == tpgrp)
	    break;

	tstat = signal (SIGTTIN, SIG_DFL);
	(void) kill (0, SIGTTIN);
	(void) signal (SIGTTIN, tstat);
    }
    
    (void) signal (SIGTTIN, SIG_IGN);
    (void) signal (SIGTTOU, SIG_IGN);
    (void) signal (SIGTSTP, SIG_IGN);
#endif	/* TIOCGPGRP */
}


sideground () {
#ifdef	TIOCGPGRP
    (void) signal (SIGTTIN, SIG_DFL);
    (void) signal (SIGTTOU, SIG_DFL);
    (void) signal (SIGTSTP, SIG_DFL);
#endif	/* TIOCGPGRP */
}

/*    SIGNALS */

/* ARGSUSED */

static TYPESIG  ALRMser (sig)
int     sig;
{
     longjmp (PEERctx, DONE);
}


#ifdef	BSD42
/* ARGSUSED */
#endif	/* BSD42 */

static TYPESIG  PIPEser (sig)
int	sig;
{
#ifndef BSD42
    (void) signal (sig, SIG_IGN);
#endif	/* BSD42 */

    adios (NULLCP, "lost peer");
}


#ifdef	BSD42
/* ARGSUSED */
#endif	/* BSD42 */

static TYPESIG  SIGser (sig)
int     sig;
{
#ifndef	BSD42
    (void) signal (sig, SIG_IGN);
#endif	/* BSD42 */

    done (1);
}


#ifdef	SIGTSTP
static TYPESIG  TSTPser (sig)
int     sig;
{
#ifndef	TERMINFO
    tputs (tgoto (CM, 0, LINES - 1), 0, _putchar);
#else	/* TERMINFO */
    move(LINES - 1, 0);	/* to lower left corner */
    clrtoeol();		/* clear bottom line */
    wrefresh(curscr);	/* flush out everything */
#endif	/* TERMINFO */
    (void) fflush (stdout);

    TTYoff ();
#ifdef	BSD42
    (void) sigsetmask (sigblock (0) & ~sigmask (SIGTSTP));
#endif	/* BSD42 */

    (void) kill (getpid (), sig);

#ifdef	BSD42
    (void) sigblock (sigmask (SIGTSTP));
#endif	/* BSD42 */
    TTYon ();

    wrefresh (curscr);
}
#endif	/* SIGTSTP */

/*    MISCELLANY */

void	done (status)
int	status;
{
    TTYoff ();
    (void) pFIN ();

    exit (status);
}

/*  */

/* VARARGS2 */

static void  adorn (what, fmt, a, b, c, d, e, f)
char   *what,
       *fmt,
       *a,
       *b,
       *c,
       *d,
       *e,
       *f;
{
    char   *cp = invo_name;

    invo_name = NULL;
    advise (what, fmt, a, b, c, d, e, f);
    invo_name = cp;
}

/*  */

/* VARARGS3 */

#if !defined(BSD42) && !defined(SVR4)
static int writev();
#endif

void advertise (what, tail, fmt, a, b, c, d, e, f)
char   *what,
       *tail,
       *fmt,
       *a,
       *b,
       *c,
       *d,
       *e,
       *f;
{
    int	    eindex = errno;
    char    buffer[BUFSIZ],
            err[BUFSIZ];
    struct iovec    iob[20];
    register struct iovec  *iov = iob;

    (void) fflush (stdout);

    (void) fflush (stderr);

    if (invo_name) {
	iov -> iov_len = strlen (iov -> iov_base = invo_name);
	iov++;
	iov -> iov_len = strlen (iov -> iov_base = ": ");
	iov++;
    }
    
    (void) sprintf (buffer, fmt, a, b, c, d, e, f);
    iov -> iov_len = strlen (iov -> iov_base = buffer);
    iov++;
    if (what) {
	if (*what) {
	    iov -> iov_len = strlen (iov -> iov_base = " ");
	    iov++;
	    iov -> iov_len = strlen (iov -> iov_base = what);
	    iov++;
	    iov -> iov_len = strlen (iov -> iov_base = ": ");
	    iov++;
	}
	if (eindex > 0 && eindex < sys_nerr)
	    iov -> iov_len = strlen (iov -> iov_base = (char *) sys_errlist[eindex]);
	else {
	    (void) sprintf (err, "Error %d", eindex);
	    iov -> iov_len = strlen (iov -> iov_base = err);
	}
	iov++;
    }
    if (tail && *tail) {
	iov -> iov_len = strlen (iov -> iov_base = ", ");
	iov++;
	iov -> iov_len = strlen (iov -> iov_base = tail);
	iov++;
    }
    iov -> iov_len = strlen (iov -> iov_base = "\n");
    iov++;

    if (tty_ready == DONE)
	(void) WINwritev (Display, iob, iov - iob);
    else
	(void) writev (fileno (stderr), iob, iov - iob);
}

/*  */

#if !defined(BSD42) && !defined(SVR4)
static int     writev (fd, iov, n)
register int     fd;
register struct iovec   *iov;
register int     n;
{
    register int    i,
                    j;

    for (i = j = 0; i < n; i++, iov++)
	if (write (fd, iov -> iov_base, iov -> iov_len) != iov -> iov_len)
	    break;
	else
	    j += iov -> iov_len;

    return j;
}
#endif	/* BSD42 || SVR4 */