/*
* wmh.c -- window front-end to nmh
*
* $Id: wmh.c,v 1.5 2003/09/30 16:57:26 gbburkhardt Exp $
*
* This code is Copyright (c) 2002, by the authors of nmh. See the
* COPYRIGHT file in the root directory of the nmh distribution for
* complete copyright information.
*/
/*
* TODO:
* Pass signals to client during execution
*
* Figure out a way for the user to say how big the Scan/Display
* windows should be, and where all the windows should be.
*/
#include <h/mh.h>
#include <h/signals.h>
#include <h/vmhsbr.h>
#include <errno.h>
#include <setjmp.h>
#include <signal.h>
#include <sys/uio.h>
#include <vt.h>
#include <bitmap.h>
#include <tools.h>
#define ALARM ((unsigned int) 10)
#define PAUSE ((unsigned int) 2)
#define SZ(a) (sizeof a / sizeof a[0])
static struct swit switches[] = {
#define PRMPTSW 0
{ "prompt string", 6 },
#define PROGSW 1
{ "vmhproc program", 7 },
#define NPROGSW 2
{ "novmhproc", 9 },
#define VERSIONSW 3
{ "version", 0 },
#define HELPSW 4
{ "help", 0 },
{ NULL, NULL }
};
/* PEERS */
static int PEERpid = NOTOK;
static jmp_buf PEERctx;
/* WINDOWS */
static int dfd = NOTOK;
static int twd = NOTOK;
static char *myprompt = "(%s) ";
struct line {
int l_no;
char *l_buf;
struct line *l_prev;
struct line *l_next;
};
#define W_NULL 0x00
#define W_CMND 0x01
#define W_FAKE 0x02
#define W_EBAR 0x04
typedef struct {
int w_fd;
int w_flags;
int w_wd;
struct wstate w_ws;
char *w_eb;
int w_ebloc;
int w_ebsize;
int w_cbase;
int w_height;
int w_cheight;
int w_width;
int w_cwidth;
struct line *w_head;
struct line *w_top;
struct line *w_bottom;
struct line *w_tail;
char w_buffer[BUFSIZ];
int w_bufpos;
} WINDOW;
static WINDOW *Scan;
static WINDOW *Status;
static WINDOW *Display;
static WINDOW *Command;
#define NWIN 4
static int numwins;
WINDOW *windows[NWIN + 1];
WINDOW *WINnew ();
#ifdef HAVE_TERMIOS_H
static struct termios tio;
# define ERASE tio.c_cc[VERASE]
# define KILL tio.c_cc[VKILL]
# define INTR tio.c_cc[VINTR]
#else
# ifdef HAVE_TERMIO_H
static struct termio tio;
# define ERASE tio.c_cc[VERASE]
# define KILL tio.c_cc[VKILL]
# define INTR tio.c_cc[VINTR]
# else
static struct sgttyb tio;
static struct tchars tc;
# define ERASE tio.sg_erase
# define KILL tio.sg_kill
# define INTR tc.t_intrc
# define EOFC tc.t_eofc
# endif
#endif
#define WERASC ltc.t_werasc
static struct ltchars ltc;
int ALRMser (), PIPEser (), SIGser ();
int ADJser (), REFser ();
/*
* static prototypes
*/
static void adorn(char *, char *, ...);
int
main (int argc, char **argv)
{
int vecp = 1, nprog = 0;
char *cp, buffer[BUFSIZ], **argp;
char **arguments, *vec[MAXARGS];
#ifdef LOCALE
setlocale(LC_ALL, "");
#endif
invo_name = r1bindex (argv[0], '/');
/* read user profile/context */
context_read();
arguments = getarguments (invo_name, argc,argv, 1);
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:
snprintf (buffer, sizeof(buffer), "%s [switches for vmhproc]",
invo_name);
print_help (buffer, switches, 1);
done (1);
case VERSIONSW:
print_version(invo_name);
done (1);
case PRMPTSW:
if (!(myprompt = *argp++) || *myprompt == '-')
adios (NULL, "missing argument to %s", argp[-2]);
continue;
case PROGSW:
if (!(vmhproc = *argp++) || *vmhproc == '-')
adios (NULL, "missing argument to %s", argp[-2]);
continue;
case NPROGSW:
nprog++;
continue;
}
else
vec[vecp++] = cp;
SIGinit ();
if (WINinit (nprog) == NOTOK) {
vec[vecp] = NULL;
vec[0] = r1bindex (vmhproc, '/');
execvp (vmhproc, vec);
adios (vmhproc, "unable to exec");
}
PEERinit (vecp, vec);
vmh ();
return done (0);
}
static void
vmh (void)
{
char buffer[BUFSIZ], prompt[BUFSIZ];
for (;;) {
pLOOP (RC_QRY, NULL);
snprintf (prompt, sizeof(prompt), myprompt, invo_name);
switch (WINgetstr (Command, prompt, buffer)) {
case NOTOK:
break;
case OK:
done (0); /* NOTREACHED */
default:
if (*buffer)
pLOOP (RC_CMD, buffer);
break;
}
}
}
/* PEERS */
static int
PEERinit (int vecp, char *vec[])
{
int pfd0[2], pfd1[2];
char buf1[BUFSIZ], buf2[BUFSIZ];
register WINDOW **w;
SIGNAL (SIGPIPE, PIPEser);
if (pipe (pfd0) == NOTOK || pipe (pfd1) == NOTOK)
adios ("pipe", "unable to");
switch (PEERpid = vfork ()) {
case NOTOK:
adios ("vfork", "unable to");/* NOTREACHED */
case OK:
for (w = windows; *w; w++)
if ((*w)->w_fd != NOTOK)
close ((*w)->w_fd);
close (pfd0[0]);
close (pfd1[1]);
vec[vecp++] = "-vmhread";
snprintf (buf1, sizeof(buf1), "%d", pfd1[0]);
vec[vecp++] = buf1;
vec[vecp++] = "-vmhwrite";
snprintf (buf2, sizeof(buf2), "%d", pfd0[1]);
vec[vecp++] = buf2;
vec[vecp] = NULL;
SIGNAL (SIGINT, SIG_DFL);
SIGNAL (SIGQUIT, SIG_DFL);
SIGNAL (SIGTERM, SIG_DFL);
vec[0] = r1bindex (vmhproc, '/');
execvp (vmhproc, vec);
perror (vmhproc);
_exit (-1); /* NOTREACHED */
default:
close (pfd0[1]);
close (pfd1[0]);
rcinit (pfd0[0], pfd1[1]);
return pINI ();
}
}
static int
pINI (void)
{
int len, buflen;
char *bp, buffer[BUFSIZ];
struct record rcs, *rc;
WINDOW **w;
rc = &rcs;
initrc (rc);
/* Get buffer ready to go */
bp = buffer;
buflen = sizeof(buffer);
snprintf (bp, buflen, "%d %d", RC_VRSN, numwins);
len = strlen (bp);
bp += len;
buflen -= len;
for (w = windows; *w; w++) {
snprintf (bp, buflen, " %d", (*w)->w_height);
len = strlen (bp);
bp += len;
buflen -= len;
}
switch (str2rc (RC_INI, buffer, rc)) {
case RC_ACK:
return OK;
case RC_ERR:
if (rc->rc_len)
adios (NULL, "%s", rc->rc_data);
else
adios (NULL, "pINI peer error");
case RC_XXX:
adios (NULL, "%s", rc->rc_data);
default:
adios (NULL, "pINI protocol screw-up");
}
/* NOTREACHED */
}
static int
pLOOP (char code, char *str)
{
int i;
struct record rcs, *rc;
WINDOW *w;
rc = &rcs;
initrc (rc);
str2peer (code, str);
for (;;)
switch (peer2rc (rc)) {
case RC_TTY:
if (pTTY () == NOTOK)
return NOTOK;
break;
case RC_WIN:
if (sscanf (rc->rc_data, "%d", &i) != 1
|| i <= 0
|| i > numwins) {
fmt2peer (RC_ERR, "no such window \"%s\"", rc->rc_data);
return NOTOK;
}
if ((w = windows[i - 1])->w_flags & W_CMND) {
fmt2peer (RC_ERR, "not a display window \"%s\"", rc->rc_data);
return NOTOK;
}
if (pWIN (w) == NOTOK)
return NOTOK;
break;
case RC_EOF:
return OK;
case RC_ERR:
if (rc->rc_len)
adorn (NULL, "%s", rc->rc_data);
else
adorn (NULL, "pLOOP(%s) peer error",
code == RC_QRY ? "QRY" : "CMD");
return NOTOK;
case RC_FIN:
if (rc->rc_len)
adorn (NULL, "%s", rc->rc_data);
rcdone ();
i = pidwait (PEERpid, OK);
PEERpid = NOTOK;
done (i);
case RC_XXX:
adios (NULL, "%s", rc->rc_data);
default:
adios (NULL, "pLOOP(%s) protocol screw-up",
code == RC_QRY ? "QRY" : "CMD");
}
}
static int
pTTY (void)
{
SIGNAL_HANDLER hstat, istat, qstat, tstat;
struct record rcs, *rc;
rc = &rcs;
initrc (rc);
if (ChangeWindowDepth (dfd, twd, 0) == NOTOK)
adios ("failed", "ChangeWindowDepth");
/* should block here instead of ignore */
hstat = SIGNAL (SIGHUP, SIG_IGN);
istat = SIGNAL (SIGINT, SIG_IGN);
qstat = SIGNAL (SIGQUIT, SIG_IGN);
tstat = SIGNAL (SIGTERM, SIG_IGN);
rc2rc (RC_ACK, 0, NULL, rc);
SIGNAL (SIGHUP, hstat);
SIGNAL (SIGINT, istat);
SIGNAL (SIGQUIT, qstat);
SIGNAL (SIGTERM, tstat);
switch (rc->rc_type) {
case RC_EOF:
rc2peer (RC_ACK, 0, NULL);
return OK;
case RC_ERR:
if (rc->rc_len)
adorn (NULL, "%s", rc->rc_data);
else
adorn (NULL, "pTTY peer error");
return NOTOK;
case RC_XXX:
adios (NULL, "%s", rc->rc_data);
default:
adios (NULL, "pTTY protocol screw-up");
}
/* NOTREACHED */
}
static int
pWIN (WINDOW *w)
{
int i;
if ((i = pWINaux (w)) == OK)
WINless (w);
return i;
}
static int
pWINaux (WINDOW *w)
{
register int n;
register char *bp;
register struct line *lp, *mp;
struct record rcs, *rc;
rc = &rcs;
initrc (rc);
for (lp = w->w_head; lp; lp = mp) {
mp = lp->l_next;
free (lp->l_buf);
free ((char *) lp);
}
w->w_head = w->w_top = w->w_bottom = w->w_tail = NULL;
w->w_bufpos = 0;
for (;;)
switch (rc2rc (RC_ACK, 0, NULL, rc)) {
case RC_DATA:
for (bp = rc->rc_data, n = rc->rc_len; n-- > 0; )
WINputc (w, *bp++);
break;
case RC_EOF:
rc2peer (RC_ACK, 0, NULL);
if (w->w_bufpos)
WINputc (w, '\n');
return OK;
case RC_ERR:
if (rc->rc_len)
adorn (NULL, "%s", rc->rc_data);
else
adorn (NULL, "pWIN peer error");
return NOTOK;
case RC_XXX:
adios (NULL, "%s", rc->rc_data);
default:
adios (NULL, "pWIN protocol screw-up");
}
/* NOTREACHED */
}
static int
pFIN (void)
{
int status;
if (PEERpid <= OK)
return OK;
rc2peer (RC_FIN, 0, NULL);
rcdone ();
switch (setjmp (PEERctx)) {
case OK:
SIGNAL (SIGALRM, ALRMser);
alarm (ALARM);
status = pidwait (PEERpid, OK);
alarm (0);
break;
default:
kill (PEERpid, SIGKILL);
status = NOTOK;
break;
}
PEERpid = NOTOK;
return status;
}
/* WINDOWS */
/* should dynamically determine all this stuff from gconfig... */
#define MyX 20 /* anchored hpos */
#define MyY 40 /* .. vpos */
#define MyW 800 /* .. width */
#define MyH 500 /* .. height */
#define MyS 30 /* .. height for Status, about one line */
#define MySlop 45 /* slop */
#define EWIDTH 25 /* Width of vertical EBAR */
#define ESLOP 5 /* .. slop */
static intWINinit (nprog) {
short wx, wy, wh, sy;
struct gconfig gc;
if (GetGraphicsConfig (fileno (stderr), &gc) == NOTOK)
if (nprog)
return NOTOK;
else
adios (NULL, "not a window");
if ((dfd = open ("/dev/ttyw0", O_RDWR)) == NOTOK)
adios ("/dev/ttyw0", "unable to open");
if ((twd = GetTopWindow (dfd)) == NOTOK)
adios ("failed", "GetTopWindow");
BlockRefreshAdjust (1);
numwins = 0;
wx = gc.w - (MyX + MyW + EWIDTH + ESLOP);
Scan = WINnew (wx, wy = MyY, MyW, wh = MyH * 2 / 3, "Scan", W_EBAR);
wy += wh + MySlop;
Status = WINnew (wx, sy = wy, MyW, wh = MyS, "Status", W_FAKE);
wy += wh + MySlop;
Display = WINnew (wx, wy, MyW, MyH, "Display", W_EBAR);
Command = WINnew (wx, sy, MyW, MyS, invo_name, W_CMND);
windows[numwins] = NULL;
return OK;
}
WINDOW *
WINnew (short wx, short wy, short ww, short wh, char *name, int flags)
{
register WINDOW *w;
if ((w = (WINDOW *) calloc (1, sizeof *w)) == NULL)
adios (NULL, "unable to allocate window");
if ((w->w_flags = flags) & W_FAKE) {
w->w_fd = NOTOK;
w->w_height = 1;
goto out;
}
if (w->w_flags & W_EBAR)
ww += EWIDTH + ESLOP;
else
wx += EWIDTH + ESLOP;
if ((w->w_fd = OpenWindow (wx, wy, ww, wh, name)) == NOTOK)
adios ("failed", "OpenWindow");
if ((w->w_wd = GetTopWindow (dfd)) == NOTOK)
adios ("failed", "GetTopWindow");
if (GetWindowState (w->w_fd, &w->w_ws) == NOTOK)
adios ("failed", "GetWindowState");
if (SetLineDisc (w->w_fd, TWSDISC) == NOTOK)
adios ("failed", "SetLineDisc");
SetBuf (w->w_fd, 1024);
SetAdjust (w->w_fd, numwins, ADJser);
SetRefresh (w->w_fd, numwins, REFser);
SetAddressing (w->w_fd, VT_ABSOLUTE);
if (w->w_flags & W_EBAR) {
w->w_eb = CreateElevatorBar (w->w_fd, 0, 0, EWIDTH,
w->w_ws.height, VT_Gray50, 1, EB_VERTICAL,
EB_ARROWS, w->w_ebloc = 0, w->w_ebsize = EB_MAX,
VT_White);
if (w->w_eb == NULL)
adios (NULL, "CreateElevatorBar failed");
RefreshElevatorBar (w->w_eb);
}
if ((w->w_cbase = CharacterBaseline (w->w_ws.font)) <= 0)
w->w_cbase = 14;
if ((w->w_cheight = CharacterHeight (w->w_ws.font)) <= 0)
w->w_cheight = 20;
w->w_height = w->w_ws.height / w->w_cheight;
if (w->w_height < 1)
w->w_height = 1;
/* 1 em */
if ((w->w_cwidth = CharacterWidth (w->w_ws.font, 'm')) <= 0)
w->w_cwidth = 10;
w->w_width = (w->w_ws.width - (w->w_eb ? (EWIDTH + ESLOP) : 0))
/ w->w_cwidth;
if (w->w_width < 1)
w->w_width = 1;
out: ;
windows[numwins++] = w;
return w;
}
static int
WINgetstr (WINDOW *w, char *prompt, char *buffer)
{
register int c;
register char *bp, *ip;
char image[BUFSIZ];
struct vtseq vts;
register struct vtseq *vt = &vts;
if (w->w_eb != NULL)
adios (NULL, "internal error--elevator bar found");
if (w->w_head == NULL
&& (w->w_head = (struct line *) calloc (1, sizeof *w->w_head))
== NULL)
adios (NULL, "unable to allocate line storage");
w->w_head->l_buf = image;
w->w_top = w->w_bottom = w->w_tail = w->w_head;
if (ChangeWindowDepth (dfd, w->w_wd, 0) == NOTOK)
adios ("failed", "ChangeWindowDepth");
strncpy (image, prompt, sizeof(image));
bp = ip = image + strlen (image);
Redisplay (w, 0);
for (;;)
switch (getvtseq (w->w_fd, vt)) {
case VT_HARDKEY:
DisplayStatus (w->w_fd, "no hardkeys, please");
break;
case VT_ASCII:
switch (c = toascii (vt->u.ascii)) {
case '\f': /* refresh? */
break;
case '\r':
case '\n':
strcpy (buffer, ip);
return DONE;
default:
if (c == INTR) {
adorn (NULL, "Interrupt");
return NOTOK;
}
if (c == EOFC) {
if (bp <= ip)
return OK;
break;
}
if (c == ERASE) {
if (bp <= ip)
continue;
bp--;
break;
}
if (c == KILL) {
if (bp <= ip)
continue;
bp = ip;
break;
}
if (c == WERASC) {
if (bp <= ip)
continue;
do {
bp--;
} while (isspace (*bp) && bp > ip);
if (bp > ip) {
do {
bp--;
} while (!isspace (*bp) && bp > buffer);
if (isspace (*bp))
bp++;
}
break;
}
if (c < ' ' || c >= '\177')
continue;
*bp++ = c;
break;
}
*bp = NULL;
Redisplay (w, 0);
break;
case VT_MOUSE:
switch (vt->u.mouse.buttons
& (VT_MOUSE_LEFT | VT_MOUSE_MIDDLE | VT_MOUSE_RIGHT)) {
case VT_MOUSE_LEFT:
DisplayStatus (w->w_fd, "use middle or right button");
break;
#define WPOP "WMH\0Advance\0Burst\0Exit\0EOF\0"
case VT_MOUSE_MIDDLE:
SetPosition (w->w_fd, vt->u.mouse.x,
vt->u.mouse.y);
switch (DisplayPopUp (w->w_fd, WPOP)) {
case 1: /* Advance */
do_advance: ;
strcpy (buffer, "advance");
return DONE;
case 2: /* Burst */
strcpy (buffer, "burst");
return DONE;
case 3: /* Exit */
strcpy (buffer, "exit");
return DONE;
case 4: /* EOF */
return OK;
default: /* failed or none taken */
break;
}
break;
#undef WPOP
case VT_MOUSE_RIGHT:
goto do_advance;
}
break;
case VT_EOF:
adios (NULL, "end-of-file on window");/* NOTREACHED */
default:
DisplayStatus (w->w_fd, "unknown VT sequence");
break;
}
}
static int
WINputc (WINDOW *w, char c)
{
register int i;
register char *cp;
register struct line *lp;
switch (c) {
default:
if (!isascii (c)) {
if (WINputc (w, 'M') == NOTOK || WINputc (w, '-') == NOTOK)
return NOTOK;
c = toascii (c);
}
else
if (c < ' ' || c == '\177') {
if (WINputc (w, '^') == NOTOK)
return NOTOK;
c ^= 0100;
}
break;
case '\t':
for (i = 8 - (w->w_bufpos & 0x07); i > 0; i--)
if (WINputc (w, ' ') == NOTOK)
return NOTOK;
return OK;
case '\b':
if (w->w_bufpos > 0)
w->w_bufpos--;
return OK;
case '\n':
break;
}
if (c != '\n') {
w->w_buffer[w->w_bufpos++] = c;
return OK;
}
w->w_buffer[w->w_bufpos] = NULL;
w->w_bufpos = 0;
if ((lp = (struct line *) calloc (1, sizeof *lp)) == NULL)
adios (NULL, "unable to allocate line storage");
lp->l_no = (w->w_tail ? w->w_tail->l_no : 0) + 1;
lp->l_buf = getcpy (w->w_buffer);
for (cp = lp->l_buf + strlen (lp->l_buf) - 1; cp >= lp->l_buf; cp--)
if (isspace (*cp))
*cp = NULL;
else
break;
if (w->w_head == NULL)
w->w_head = lp;
if (w->w_top == NULL)
w->w_top = lp;
if (w->w_bottom == NULL)
w->w_bottom = lp;
if (w->w_tail)
w->w_tail->l_next = lp;
lp->l_prev = w->w_tail;
w->w_tail = lp;
return DONE;
}
#define PSLOP 2
static char mylineno[5];
static bool cancel[] = { 1 };
static struct choice mychoices[] = { LABEL, "cancel", VT_White };
static struct question myquestions[] = {
STRING, "Line", SZ (mylineno), (struct choice *) 0,
TOGGLE, "", SZ (mychoices), mychoices
};
static struct menu mymenu = { "Goto", SZ (myquestions), myquestions };
static int *myanswers[] = { (int *) mylineno, (int *) cancel };
static void
WINless (WINDOW *w)
{
int clear, pos, forw, refresh;
struct vtseq vts;
register struct vtseq *vt = &vts;
if (w->w_fd == NOTOK) {
if (w->w_head)
DisplayStatus (dfd, w->w_top->l_buf);
else
RemoveStatus (dfd);
return;
}
if (ChangeWindowDepth (dfd, w->w_wd, 0) == NOTOK)
adios ("failed", "ChangeWindowDepth");
Redisplay (w, 0);
if (w->w_bottom == w->w_tail)
return;
if (w->w_eb == NULL)
adios (NULL, "internal error--no elevator bar");
for (clear = refresh = 0, forw = 1;;) {
if (clear) {
RemoveStatus (w->w_fd);
clear = 0;
}
if (refresh) {
Redisplay (w, 0);
refresh = 0;
}
switch (getvtseq (w->w_fd, vt)) {
case VT_HARDKEY:
case VT_ASCII:
DisplayStatus (w->w_fd, "use the mouse");
clear++;
break;
case VT_MOUSE:
switch (vt->u.mouse.buttons
& (VT_MOUSE_LEFT | VT_MOUSE_MIDDLE | VT_MOUSE_RIGHT)) {
case VT_MOUSE_LEFT:
if ((pos = vt->u.mouse.x) < EWIDTH) {
pos = w->w_ebloc = DoElevatorBar (w->w_eb, pos,
vt->u.mouse.y);
refresh = WINgoto (w, ((pos * (w->w_tail->l_no
- w->w_head->l_no))
/ EB_MAX) + w->w_head->l_no);
}
break;
#define WPOP "Paging\0Next\0Prev\0Left\0Right\0First\0Last\0Goto ...\0Exit\0"
case VT_MOUSE_MIDDLE:
SetPosition (w->w_fd, vt->u.mouse.x,
vt->u.mouse.y);
switch (DisplayPopUp (w->w_fd, WPOP)) {
case 1: /* Next */
do_next_page: ;
if (w->w_bottom == w->w_tail)
forw = 0;
refresh = WINgoto (w, w->w_bottom->l_no + 1 - PSLOP);
break;
case 2: /* Prev */
do_prev_page: ;
if (w->w_top == w->w_head)
forw = 1;
refresh = WINgoto (w, w->w_top->l_no
- w->w_height + PSLOP);
break;
case 3: /* Left */
case 4: /* Right */
DisplayStatus (w->w_fd, "not yet");
clear++;
break;
case 5: /* First */
forw = 1;
refresh = WINgoto (w, w->w_head->l_no);
break;
case 6: /* Last */
forw = 0;
refresh = WINgoto (w, w->w_tail->l_no
- w->w_height + 1);
break;
case 7: /* Goto ... */
snprintf (mylineno, sizeof(mylineno),
"%d", w->w_top->l_no);
cancel[0] = 0;
if (PresentMenu (&mymenu, myanswers)
|| cancel[0])
break;
if (sscanf (mylineno, "%d", &pos) != 1) {
DisplayStatus (w->w_fd, "bad format");
clear++;
break;
}
if (pos < w->w_head->l_no
|| pos > w->w_tail->l_no) {
DisplayStatus (w->w_fd, "no such line");
clear++;
break;
}
refresh = WINgoto (w, pos);
break;
case 8: /* Exit */
return;
default: /* failed or none taken */
break;
}
break;
#undef WPOP
case VT_MOUSE_RIGHT:
if (forw) {
if (w->w_bottom == w->w_tail)
return;
else
goto do_next_page;
}
else
goto do_prev_page;
}
break;
case VT_EOF:
adios (NULL, "end-of-file on window");/* NOTREACHED */
default:
DisplayStatus (w->w_fd, "unknown VT sequence");
clear++;
break;
}
}
}
static int
WINgoto (WINDOW *w, int n)
{
register int i, j;
register struct line *lp;
if (n > (i = w->w_tail->l_no - w->w_height + 1))
n = i;
if (n < w->w_head->l_no)
n = w->w_head->l_no;
if ((i = n - (lp = w->w_head)->l_no)
> (j = abs (n - w->w_top->l_no)))
i = j, lp = w->w_top;
if (i > (j = abs (w->w_tail->l_no - n)))
i = j, lp = w->w_tail;
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 = w->w_head;
}
if (w->w_top == lp)
return 0;
w->w_top = lp;
return 1;
}
static int
ADJser (int id, short ww, short wh)
{
register WINDOW *w;
if (id < 0 || id >= numwins)
adios (NULL, "ADJser on bogus window (%d)", id);
w = windows[id];
if (w->w_fd == NOTOK)
adios (NULL, "ADJser on closed window (%d)", id);
w->w_ws.width = w->w_ws.tw = ww;
w->w_ws.height = w->w_ws.th = wh;
if (w->w_eb) {
DeleteElevatorBar (w->w_eb);
w->w_eb = CreateElevatorBar (w->w_fd, 0, 0, EWIDTH,
w->w_ws.height, VT_Gray50, 1, EB_VERTICAL,
EB_ARROWS, w->w_ebloc = 0, w->w_ebsize = EB_MAX,
VT_White);
if (w->w_eb == NULL)
adios (NULL, "CreateElevatorBar failed");
}
Redisplay (w, 1);
}
static int
REFser (int id, short wx, short wy, short ww, short wh)
{
short cx, cy, cw, ch;
register WINDOW *w;
if (id < 0 || id >= numwins)
adios (NULL, "REFser on bogus window (%d)", id);
w = windows[id];
if (w->w_fd == NOTOK)
adios (NULL, "REFser on closed window (%d)", id);
if (GetWindowState (w->w_fd, &w->w_ws) == NOTOK)
adios ("failed", "GetWindowState");
GetPermanentClipping (w->w_fd, &cx, &cy, &cw, &ch);
SetPermanentClipping (w->w_fd, wx, wy, ww, wh);
Redisplay (w, 1);
SetPermanentClipping (w->w_fd, cx, cy, cw, ch);
}
static void
Redisplay (WINDOW *w, int doeb)
{
register int y;
short sx;
register struct line *lp;
if (w->w_fd == NOTOK)
return;
sx = w->w_eb ? (EWIDTH + ESLOP) : 0;
w->w_height = w->w_ws.height / w->w_cheight;
if (w->w_height < 1)
w->w_height = 1;
w->w_width = (w->w_ws.width - (w->w_eb ? (EWIDTH + ESLOP) : 0))
/ w->w_cwidth;
if (w->w_width < 1)
w->w_width = 1;
SetPosition (w->w_fd, sx, 0);
SetColor (w->w_fd, VT_White);
PaintRectangleInterior (w->w_fd, w->w_ws.width, w->w_ws.height);
if (w->w_head) {
SetColor (w->w_fd, VT_Black);
for (lp = w->w_top, y = 0;
lp && y < w->w_height;
w->w_bottom = lp, lp = lp->l_next, y++) {
SetPosition (w->w_fd, sx, y * w->w_cheight + w->w_cbase);
PaintString (w->w_fd, VT_STREND, lp->l_buf);
}
}
if (w->w_eb) {
if ((y = EB_LOC (w)) != w->w_ebloc)
MoveElevator (w->w_eb, w->w_ebloc = y);
if ((y = EB_SIZE (w)) != w->w_ebsize)
SizeElevator (w->w_eb, w->w_ebsize = y);
if (doeb)
RefreshElevatorBar (w->w_eb);
}
Flush (w->w_fd);
}
static int
EB_SIZE (WINDOW *w)
{
register int i;
if (w->w_head == NULL)
return 0;
if ((i = w->w_tail->l_no - w->w_head->l_no) <= 0)
return EB_MAX;
return (((w->w_bottom->l_no - w->w_top->l_no) * EB_MAX) / i);
}
static int
EB_LOC (WINDOW *w)
{
register int i;
if (w->w_head == NULL)
return 0;
if ((i = w->w_tail->l_no - w->w_head->l_no) <= 0)
return EB_MAX;
return (((w->w_top->l_no - w->w_head->l_no) * EB_MAX) / i);
}
/* SIGNALS */
static void
SIGinit (void)
{
foreground ();
if (ioctl (fileno (stdin), TIOCGETP, (char *) &tio) == NOTOK)
adios ("failed", "ioctl TIOCGETP");
if (ioctl (fileno (stdin), TIOCGETC, (char *) &tc) == NOTOK)
adios ("failed", "ioctl TIOCGETC");
if (ioctl (fileno (stdin), TIOCGLTC, (char *) <c) == NOTOK)
adios ("failed", "ioctl TIOCGLTC");
sideground ();
SIGNAL (SIGHUP, SIGser);
SIGNAL (SIGINT, SIGser);
SIGNAL (SIGQUIT, SIGser);
}
static void
foreground (void)
{
#ifdef TIOCGPGRP
int pgrp, tpgrp;
SIGNAL_HANDLER 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);
kill (0, SIGTTIN);
SIGNAL (SIGTTIN, tstat);
}
SIGNAL (SIGTTIN, SIG_IGN);
SIGNAL (SIGTTOU, SIG_IGN);
SIGNAL (SIGTSTP, SIG_IGN);
#endif TIOCGPGRP
}
static void
sideground (void)
{
#ifdef TIOCGPGRP
SIGNAL (SIGTTIN, SIG_DFL);
SIGNAL (SIGTTOU, SIG_DFL);
SIGNAL (SIGTSTP, SIG_DFL);
#endif TIOCGPGRP
}
static int
ALRMser (int sig)
{
longjmp (PEERctx, DONE);
}
static int
PIPEser (int sig)
{
#ifndef RELIABLE_SIGNALS
SIGNAL (sig, SIG_IGN);
#endif
adios (NULL, "lost peer");
}
static int
SIGser (int sig)
{
#ifndef RELIABLE_SIGNALS
SIGNAL (sig, SIG_IGN);
#endif
done (1);
}
int
done (int status)
{
if (dfd != NOTOK)
RemoveStatus (dfd);
pFIN ();
exit (status);
return 1; /* dead code to satisfy the compiler */
}
static void
adorn (char *what, char *fmt, ...)
{
va_list ap
char *cp;
cp = invo_name;
invo_name = NULL;
va_start(ap, fmt);
advertise (what, NULL, fmt, ap);
va_end(ap);
invo_name = cp;
}
void
advertise (char *what, char *tail, va_list ap)
{
int eindex = errno;
char buffer[BUFSIZ], err[BUFSIZ];
struct iovec iob[20];
register struct iovec *iov = iob;
fflush (stdout);
fflush (stderr);
if (invo_name) {
iov->iov_len = strlen (iov->iov_base = invo_name);
iov++;
iov->iov_len = strlen (iov->iov_base = ": ");
iov++;
}
vsnprintf (buffer, sizeof(buffer), fmt, ap);
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 (!(iov->iov_base = strerror (eindex))) {
snprintf (err, sizeof(err), "unknown error %d", eindex);
iov->iov_base = err;
}
iov->iov_len = strlen (iov->iov_base);
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 (dfd != NOTOK)
DisplayVector (iob, iov - iob);
else
writev (fileno (stderr), iob, iov - iob);
}
static void
DisplayVector (struct iovec *iov, int n)
{
register int i;
register char *cp;
char buffer[BUFSIZ];
for (i = 0, cp = NULL; i < n; i++, iov++) {
snprintf (buffer, sizeof(buffer), "%*.*s", iov->iov_len,
iov->iov_len, iov->iov_base);
cp = add (buffer, cp);
}
DisplayStatus (dfd, cp);
free (cp);
sleep (PAUSE);
RemoveStatus (dfd);
}
syntax highlighted by Code2HTML, v. 0.9.1