|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 23408 (0x5b70)
Types: TextFile
Names: »screen.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec1/screen/screen.c«
/* Copyright (c) 1987, Oliver Laumann, Technical University of Berlin.
* Not derived from licensed software.
*
* Permission is granted to freely use, copy, modify, and redistribute
* this software, provided that no attempt is made to gain profit from it,
* the author is not construed to be liable for any results of using the
* software, alterations are clearly marked as such, and this notice is
* not modified.
*/
static char ScreenVersion[] = "screen 1.1c 23-Mar-87";
#include <stdio.h>
#include <sgtty.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include "screen.h"
#define MAXWIN 10
#define MAXARGS 64
#define MAXLINE 1024
#define MSGWAIT 4
#define DEFAULT_SHELL "/bin/sh"
#define Ctrl(c) ((c)&037)
#define PtyProto "/dev/ptyXY"
#define TtyProto "/dev/ttyXY"
extern char *blank, Term[], **environ;
extern rows, cols;
extern status;
extern time_t TimeDisplayed;
extern char AnsiVersion[];
extern short ospeed;
extern errno;
extern sys_nerr;
extern char *sys_errlist[];
extern char *rindex(), *malloc(), *getenv(), *MakeTermcap(), *ttyname();
static SigChld();
static char *Filename(), **SaveArgs();
static char PtyName[32], TtyName[32];
static char *ShellProg;
static char *ShellArgs[2];
static char inbuf[IOSIZE];
static inlen;
static ESCseen;
static GotSignal;
static char SockPath[512];
static char SockDir[] = ".screen";
static char *SockName;
static char *NewEnv[MAXARGS];
static char Esc = Ctrl('a');
static char MetaEsc = 'a';
static char *home;
static HasWindow;
struct mode {
struct sgttyb m_ttyb;
struct tchars m_tchars;
struct ltchars m_ltchars;
int m_ldisc;
int m_lmode;
} OldMode, NewMode;
static struct win *curr, *other;
static CurrNum, OtherNum;
static struct win *wtab[MAXWIN];
#define MSG_CREATE 0
#define MSG_ERROR 1
struct msg {
int type;
union {
struct {
int aflag;
int nargs;
char line[MAXLINE];
} create;
char message[MAXLINE];
} m;
};
#define KEY_IGNORE 0
#define KEY_HARDCOPY 1
#define KEY_SUSPEND 2
#define KEY_SHELL 3
#define KEY_NEXT 4
#define KEY_PREV 5
#define KEY_KILL 6
#define KEY_REDISPLAY 7
#define KEY_WINDOWS 8
#define KEY_VERSION 9
#define KEY_OTHER 10
#define KEY_0 11
#define KEY_1 12
#define KEY_2 13
#define KEY_3 14
#define KEY_4 15
#define KEY_5 16
#define KEY_6 17
#define KEY_7 18
#define KEY_8 19
#define KEY_9 20
#define KEY_CREATE 21
struct key {
int type;
char **args;
} ktab[256];
char *KeyNames[] = {
"hardcopy", "suspend", "shell", "next", "prev", "kill", "redisplay",
"windows", "version", "other", "select0", "select1", "select2", "select3",
"select4", "select5", "select6", "select7", "select8", "select9",
0
};
main (ac, av) char **av; {
register n, len;
register struct win **pp, *p;
char *ap;
int s, r, w, x = 0;
int aflag = 0;
struct timeval tv;
time_t now;
char buf[IOSIZE], *myname = (ac == 0) ? "screen" : av[0];
char rc[256];
while (--ac) {
ap = *++av;
if (strcmp (ap, "-c") == 0) {
if (ac < 2)
goto help;
CheckSockName (1);
s = MakeClientSocket ();
SendCreateMsg (s, ac, av, aflag);
close (s);
exit (0);
} else if (strcmp (ap, "-a") == 0) {
aflag = 1;
} else if (ap[0] == '-' && ap[1] == 'e') {
if (ap[2]) {
ap += 2;
} else {
if (--ac == 0) goto help;
ap = *++av;
}
if (strlen (ap) != 2)
Msg (0, "Two characters are required with -e option.");
Esc = ap[0];
MetaEsc = ap[1];
} else {
help:
Msg (0, "Use: %s [-a] [-exy] [-c cmd args]", myname);
}
}
if ((ShellProg = getenv ("SHELL")) == 0)
ShellProg = DEFAULT_SHELL;
ShellArgs[0] = ShellProg;
CheckSockName (0);
s = MakeServerSocket ();
InitTerm ();
MakeNewEnv ();
GetTTY (0, &OldMode);
ospeed = (short)OldMode.m_ttyb.sg_ospeed;
InitKeytab ();
sprintf (rc, "%.*s/.screenrc", 245, home);
ReadRc (rc);
if ((n = MakeWindow (ShellProg, ShellArgs, aflag, 0)) == -1) {
SetTTY (0, &OldMode);
FinitTerm ();
exit (1);
}
SetCurrWindow (n);
HasWindow = 1;
SetMode (&OldMode, &NewMode);
SetTTY (0, &NewMode);
signal (SIGCHLD, SigChld);
tv.tv_usec = 0;
while (1) {
if (status) {
time (&now);
if (now - TimeDisplayed < MSGWAIT) {
tv.tv_sec = MSGWAIT - (now - TimeDisplayed);
} else RemoveStatus (curr);
}
r = 0;
w = 0;
if (inlen)
w |= 1 << curr->ptyfd;
else
r |= 1 << 0;
for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
if (!(p = *pp))
continue;
if ((*pp)->active && status)
continue;
if ((*pp)->outlen > 0)
continue;
r |= 1 << (*pp)->ptyfd;
}
r |= 1 << s;
fflush (stdout);
if (select (32, &r, &w, &x, status ? &tv : (struct timeval *)0) == -1) {
if (errno == EINTR)
continue;
HasWindow = 0;
Msg (errno, "select");
/*NOTREACHED*/
}
if (GotSignal && !status) {
SigHandler ();
continue;
}
if (r & 1 << s) {
RemoveStatus (curr);
ReceiveMsg (s);
}
if (r & 1 << 0) {
RemoveStatus (curr);
if (ESCseen) {
inbuf[0] = Esc;
inlen = read (0, inbuf+1, IOSIZE-1) + 1;
ESCseen = 0;
} else {
inlen = read (0, inbuf, IOSIZE);
}
if (inlen > 0)
inlen = ProcessInput (inbuf, inlen);
}
if (GotSignal && !status) {
SigHandler ();
continue;
}
for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
if (!(p = *pp))
continue;
if (p->outlen) {
WriteString (p, p->outbuf, p->outlen);
} else if (r & 1 << p->ptyfd) {
if ((len = read (p->ptyfd, buf, IOSIZE)) == -1) {
if (errno == EWOULDBLOCK)
len = 0;
}
if (len > 0)
WriteString (p, buf, len);
}
}
if (GotSignal && !status) {
SigHandler ();
continue;
}
if (w & 1 << curr->ptyfd && inlen > 0) {
if ((len = write (curr->ptyfd, inbuf, inlen)) > 0) {
inlen -= len;
bcopy (inbuf+len, inbuf, inlen);
}
}
if (GotSignal && !status)
SigHandler ();
}
/*NOTREACHED*/
}
static SigHandler () {
while (GotSignal) {
GotSignal = 0;
DoWait ();
}
}
static SigChld () {
GotSignal = 1;
}
static DoWait () {
register pid;
register struct win **pp;
union wait wstat;
while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0) {
for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
if (*pp && pid == (*pp)->wpid) {
if (WIFSTOPPED (wstat)) {
kill((*pp)->wpid, SIGCONT);
} else {
if (*pp == curr)
curr = 0;
if (*pp == other)
other = 0;
FreeWindow (*pp);
*pp = 0;
}
}
}
}
CheckWindows ();
}
static CheckWindows () {
register struct win **pp;
/* If the current window disappeared and the "other" window is still
* there, switch to the "other" window, else switch to the window
* with the lowest index.
* If there current window is still there, but the "other" window
* vanished, "SetCurrWindow" is called in order to assign a new value
* to "other".
* If no window is alive at all, exit.
*/
if (!curr && other) {
SwitchWindow (OtherNum);
return;
}
if (curr && !other) {
SetCurrWindow (CurrNum);
return;
}
for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
if (*pp) {
if (!curr)
SwitchWindow (pp-wtab);
return;
}
}
SetTTY (0, &OldMode);
FinitTerm ();
exit (0);
}
InitKeytab () {
register i;
ktab['h'].type = ktab[Ctrl('h')].type = KEY_HARDCOPY;
ktab['z'].type = ktab[Ctrl('z')].type = KEY_SUSPEND;
ktab['c'].type = ktab[Ctrl('c')].type = KEY_SHELL;
ktab[' '].type = ktab[Ctrl(' ')].type =
ktab['n'].type = ktab[Ctrl('n')].type = KEY_NEXT;
ktab['-'].type = ktab['p'].type = ktab[Ctrl('p')].type = KEY_PREV;
ktab['k'].type = ktab[Ctrl('k')].type = KEY_KILL;
ktab['l'].type = ktab[Ctrl('l')].type = KEY_REDISPLAY;
ktab['w'].type = ktab[Ctrl('w')].type = KEY_WINDOWS;
ktab['v'].type = ktab[Ctrl('v')].type = KEY_VERSION;
ktab[Esc].type = KEY_OTHER;
for (i = 0; i <= 9; i++)
ktab[i+'0'].type = KEY_0+i;
}
static ProcessInput (buf, len) char *buf; {
register n, k;
register char *s, *p;
for (s = p = buf; len > 0; len--, s++) {
if (*s == Esc) {
if (len > 1) {
len--; s++;
k = ktab[*s].type;
if (*s == MetaEsc) {
*p++ = Esc;
} else if (k >= KEY_0 && k <= KEY_9) {
p = buf;
SwitchWindow (k - KEY_0);
} else switch (ktab[*s].type) {
case KEY_HARDCOPY:
p = buf;
DumpWindow ();
break;
case KEY_SUSPEND:
p = buf;
SetTTY (0, &OldMode);
FinitTerm ();
kill (getpid (), SIGTSTP);
SetTTY (0, &NewMode);
Activate (wtab[CurrNum]);
break;
case KEY_SHELL:
p = buf;
if ((n = MakeWindow (ShellProg, ShellArgs, 0, 0)) != -1)
SwitchWindow (n);
break;
case KEY_NEXT:
p = buf;
SwitchWindow (NextWindow ());
break;
case KEY_PREV:
p = buf;
SwitchWindow (PreviousWindow ());
break;
case KEY_KILL:
p = buf;
FreeWindow (wtab[CurrNum]);
if (other == curr)
other = 0;
curr = wtab[CurrNum] = 0;
CheckWindows ();
break;
case KEY_REDISPLAY:
p = buf;
Activate (wtab[CurrNum]);
break;
case KEY_WINDOWS:
p = buf;
ShowWindows ();
break;
case KEY_VERSION:
p = buf;
Msg (0, "%s %s", ScreenVersion, AnsiVersion);
break;
case KEY_OTHER:
p = buf;
SwitchWindow (OtherNum);
break;
case KEY_CREATE:
p = buf;
if ((n = MakeWindow (ktab[*s].args[0], ktab[*s].args,
0, 0)) != -1)
SwitchWindow (n);
break;
}
} else ESCseen = 1;
} else *p++ = *s;
}
return p - buf;
}
static SwitchWindow (n) {
if (!wtab[n])
return;
SetCurrWindow (n);
Activate (wtab[n]);
}
static SetCurrWindow (n) {
/*
* If we come from another window, this window becomes the
* "other" window:
*/
if (curr) {
curr->active = 0;
other = curr;
OtherNum = CurrNum;
}
CurrNum = n;
curr = wtab[n];
curr->active = 1;
/*
* If the "other" window is currently undefined (at program start
* or because it has died), or if the "other" window is equal to the
* one just selected, we try to find a new one:
*/
if (other == 0 || other == curr) {
OtherNum = NextWindow ();
other = wtab[OtherNum];
}
}
static NextWindow () {
register struct win **pp;
for (pp = wtab+CurrNum+1; pp != wtab+CurrNum; ++pp) {
if (pp == wtab+MAXWIN)
pp = wtab;
if (*pp)
break;
}
return pp-wtab;
}
static PreviousWindow () {
register struct win **pp;
for (pp = wtab+CurrNum-1; pp != wtab+CurrNum; --pp) {
if (pp < wtab)
pp = wtab+MAXWIN-1;
if (*pp)
break;
}
return pp-wtab;
}
static FreeWindow (wp) struct win *wp; {
register i;
close (wp->ptyfd);
for (i = 0; i < rows; ++i) {
free (wp->image[i]);
free (wp->attr[i]);
}
free (wp->image);
free (wp->attr);
free (wp);
}
static MakeWindow (prog, args, aflag, StartAt) char *prog, **args; {
register struct win **pp, *p;
register char **cp;
register n, f;
int tf;
int mypid;
char ebuf[10];
pp = wtab+StartAt;
do {
if (*pp == 0)
break;
if (++pp == wtab+MAXWIN)
pp = wtab;
} while (pp != wtab+StartAt);
if (*pp) {
Msg (0, "No more windows.");
return -1;
}
n = pp - wtab;
if ((f = OpenPTY ()) == -1) {
Msg (0, "No more PTYs.");
return -1;
}
fcntl (f, F_SETFL, FNDELAY);
if ((p = *pp = (struct win *)malloc (sizeof (struct win))) == 0) {
nomem:
Msg (0, "Out of memory.");
return -1;
}
if ((p->image = (char **)malloc (rows * sizeof (char *))) == 0)
goto nomem;
for (cp = p->image; cp < p->image+rows; ++cp) {
if ((*cp = malloc (cols)) == 0)
goto nomem;
bclear (*cp, cols);
}
if ((p->attr = (char **)malloc (rows * sizeof (char *))) == 0)
goto nomem;
for (cp = p->attr; cp < p->attr+rows; ++cp) {
if ((*cp = malloc (cols)) == 0)
goto nomem;
bzero (*cp, cols);
}
if ((p->tabs = malloc (cols+1)) == 0) /* +1 because 0 <= x <= cols */
goto nomem;
ResetScreen (p);
p->active = 0;
p->outlen = 0;
p->ptyfd = f;
strncpy (p->cmd, Filename (args[0]), MAXSTR-1);
p->cmd[MAXSTR-1] = '\0';
switch (p->wpid = fork ()) {
case -1:
Msg (errno, "Cannot fork");
free (p);
return -1;
case 0:
mypid = getpid ();
if ((f = open ("/dev/tty", O_RDWR)) != -1) {
ioctl (f, TIOCNOTTY, (char *)0);
close (f);
}
if ((tf = open (TtyName, O_RDWR)) == -1) {
SendErrorMsg ("Cannot open %s: %s", TtyName, sys_errlist[errno]);
exit (1);
}
dup2 (tf, 0);
dup2 (tf, 1);
dup2 (tf, 2);
for (f = getdtablesize () - 1; f > 2; f--)
close (f);
ioctl (0, TIOCSPGRP, &mypid);
setpgrp (0, mypid);
SetTTY (0, &OldMode);
NewEnv[2] = MakeTermcap (aflag);
sprintf (ebuf, "WINDOW=%d", n);
NewEnv[3] = ebuf;
execve (prog, args, NewEnv);
SendErrorMsg ("Cannot exec %s: %s", prog, sys_errlist[errno]);
sleep (2);
exit (1);
}
return n;
}
static DumpWindow () {
register i, j, k;
register char *p;
register FILE *f;
char fn[20];
sprintf (fn, "hardcopy.%d", CurrNum);
if ((f = fopen (fn, "w")) == NULL) {
Msg (0, "Cannot open \"%s\".", fn);
return;
}
Msg (0, "Dumping screen image...");
for (i = 0; i < rows; ++i) {
p = curr->image[i];
for (k = cols-1; k >= 0 && p[k] == ' '; --k) ;
for (j = 0; j <= k; ++j)
putc (p[j], f);
putc ('\n', f);
}
fclose (f);
Msg (0, "Screen image written to \"%s\".", fn);
}
static ShowWindows () {
char buf[1024];
register char *s;
register struct win **pp, *p;
for (s = buf, pp = wtab; pp < wtab+MAXWIN; ++pp) {
if ((p = *pp) == 0)
continue;
if (s - buf + 5 + strlen (p->cmd) > cols-1)
break;
if (s > buf) {
*s++ = ' '; *s++ = ' ';
}
*s++ = pp - wtab + '0';
if (p == curr)
*s++ = '*';
*s++ = ' ';
strcpy (s, p->cmd);
s += strlen (s);
}
Msg (0, buf);
}
static OpenPTY () {
register char *p, *l, *d;
register i, f, tf;
strcpy (PtyName, PtyProto);
strcpy (TtyName, TtyProto);
for (p = PtyName, i = 0; *p != 'X'; ++p, ++i) ;
for (l = "pqr"; *p = *l; ++l) {
for (d = "0123456789abcdef"; p[1] = *d; ++d) {
if ((f = open (PtyName, O_RDWR)) != -1) {
TtyName[i] = p[0];
TtyName[i+1] = p[1];
if ((tf = open (TtyName, O_RDWR)) != -1) {
close (tf);
return f;
}
close (f);
}
}
}
return -1;
}
static SetTTY (fd, mp) struct mode *mp; {
ioctl (fd, TIOCSETP, &mp->m_ttyb);
ioctl (fd, TIOCSETC, &mp->m_tchars);
ioctl (fd, TIOCSLTC, &mp->m_ltchars);
ioctl (fd, TIOCLSET, &mp->m_lmode);
ioctl (fd, TIOCSETD, &mp->m_ldisc);
}
static GetTTY (fd, mp) struct mode *mp; {
ioctl (fd, TIOCGETP, &mp->m_ttyb);
ioctl (fd, TIOCGETC, &mp->m_tchars);
ioctl (fd, TIOCGLTC, &mp->m_ltchars);
ioctl (fd, TIOCLGET, &mp->m_lmode);
ioctl (fd, TIOCGETD, &mp->m_ldisc);
}
static SetMode (op, np) struct mode *op, *np; {
*np = *op;
np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
np->m_ttyb.sg_flags |= CBREAK;
np->m_tchars.t_intrc = -1;
np->m_tchars.t_quitc = -1;
np->m_ltchars.t_suspc = -1;
np->m_ltchars.t_dsuspc = -1;
np->m_ltchars.t_flushc = -1;
np->m_ltchars.t_lnextc = -1;
}
static CheckSockName (client) {
struct stat s;
register char *p;
if (client) {
if ((SockName = getenv ("STY")) == 0 || *SockName == '\0')
Msg (0, "$STY is undefined or invalid.");
} else {
if ((p = ttyname (0)) == 0 || (p = ttyname (1)) == 0 ||
(p = ttyname (2)) == 0 || *p == '\0')
Msg (0, "screen must run on a tty.");
SockName = Filename (p);
}
if ((home = getenv ("HOME")) == 0)
Msg (0, "$HOME is undefined.");
sprintf (SockPath, "%s/%s", home, SockDir);
if (stat (SockPath, &s) == -1) {
if (errno == ENOENT) {
if (mkdir (SockPath, 0700) == -1)
Msg (errno, "Cannot make directory %s", SockPath);
} else Msg (errno, "Cannot get status of %s", SockPath);
} else {
if ((s.st_mode & S_IFMT) != S_IFDIR)
Msg (0, "%s is not a directory.", SockPath);
if ((s.st_mode & 0777) != 0700)
Msg (0, "Directory %s must have mode 700.", SockPath);
}
strcat (SockPath, "/");
strcat (SockPath, SockName);
}
static MakeServerSocket () {
register s;
struct sockaddr_un sun;
(void) unlink (SockPath);
if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
Msg (errno, "socket");
sun.sun_family = AF_UNIX;
strcpy (sun.sun_path, SockPath);
if (bind (s, (struct sockaddr *)&sun, strlen (SockPath)+2) == -1)
Msg (errno, "bind");
if (listen (s, 5) == -1)
Msg (errno, "listen");
return s;
}
static MakeClientSocket () {
register s;
struct sockaddr_un sun;
if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
Msg (errno, "socket");
sun.sun_family = AF_UNIX;
strcpy (sun.sun_path, SockPath);
if (connect (s, (struct sockaddr *)&sun, strlen (SockPath)+2) == -1)
Msg (errno, "connect: %s", SockPath);
return s;
}
static SendCreateMsg (s, ac, av, aflag) char **av; {
struct msg m;
register char *p;
register len, n;
m.type = MSG_CREATE;
for (p = m.m.create.line, n = 0; --ac && n < MAXARGS-1; ++n) {
len = strlen (*++av) + 1;
if (p + len >= m.m.create.line+MAXLINE)
break;
strcpy (p, *av);
p += len;
}
m.m.create.nargs = n;
m.m.create.aflag = aflag;
if (write (s, &m, sizeof (m)) != sizeof (m))
Msg (errno, "write");
}
/*VARARGS1*/
static SendErrorMsg (fmt, p1, p2, p3, p4, p5, p6) char *fmt; {
register s;
struct msg m;
s = MakeClientSocket ();
m.type = MSG_ERROR;
sprintf (m.m.message, fmt, p1, p2, p3, p4, p5, p6);
(void) write (s, &m, sizeof (m));
close (s);
}
static ReceiveMsg (s) {
register ns;
struct sockaddr_un sun;
int len = sizeof (sun);
struct msg m;
if ((ns = accept (s, (struct sockaddr *)&sun, &len)) == -1) {
Msg (errno, "accept");
return;
}
if ((len = read (ns, &m, sizeof (m))) != sizeof (m)) {
if (len == -1)
Msg (errno, "read");
else
Msg (0, "Short message (%d bytes)", len);
close (ns);
return;
}
switch (m.type) {
case MSG_CREATE:
ExecCreate (&m);
break;
case MSG_ERROR:
Msg (0, "%s", m.m.message);
break;
default:
Msg (0, "Invalid message (type %d).", m.type);
}
close (ns);
}
static ExecCreate (mp) struct msg *mp; {
char *args[MAXARGS];
register n;
register char **pp = args, *p = mp->m.create.line;
for (n = mp->m.create.nargs; n > 0; --n) {
*pp++ = p;
p += strlen (p) + 1;
}
*pp = 0;
if ((n = MakeWindow (mp->m.create.line, args, mp->m.create.aflag, 0)) != -1)
SwitchWindow (n);
}
static ReadRc (fn) char *fn; {
FILE *f;
register char *p, **pp, **ap;
register argc, num, c;
char buf[256];
char *args[MAXARGS];
int key;
ap = args;
if ((f = fopen (fn, "r")) == NULL)
return;
while (fgets (buf, 256, f) != NULL) {
if (p = rindex (buf, '\n'))
*p = '\0';
if ((argc = Parse (fn, buf, ap)) == 0)
continue;
if (strcmp (ap[0], "escape") == 0) {
p = ap[1];
if (argc < 2 || strlen (p) != 2)
Msg (0, "%s: two characters required after escape.", fn);
Esc = *p++;
MetaEsc = *p;
} else if (strcmp (ap[0], "screen") == 0) {
num = 0;
if (argc > 1 && IsNum (ap[1], 10)) {
num = atoi (ap[1]);
if (num < 0 || num > MAXWIN-1)
Msg (0, "%s: illegal screen number %d.", fn, num);
--argc; ++ap;
}
if (argc < 2) {
ap[1] = ShellProg; argc = 2;
}
ap[argc] = 0;
(void) MakeWindow (ap[1], ap+1, 0, num);
} else if (strcmp (ap[0], "bind") == 0) {
p = ap[1];
if (argc < 2 || *p == '\0')
Msg (0, "%s: key expected after bind.", fn);
if (p[1] == '\0') {
key = *p;
} else if (p[0] == '^' && p[1] != '\0' && p[2] == '\0') {
c = p[1];
if (isupper (c))
p[1] = tolower (c);
key = Ctrl(c);
} else if (IsNum (p, 7)) {
(void) sscanf (p, "%o", &key);
} else {
Msg (0,
"%s: bind: character, ^x, or octal number expected.", fn);
}
if (argc < 3) {
ktab[key].type = 0;
} else {
for (pp = KeyNames; *pp; ++pp)
if (strcmp (ap[2], *pp) == 0) break;
if (*pp) {
ktab[key].type = pp-KeyNames+1;
} else if (ap[2][0] == '/') {
ktab[key].type = KEY_CREATE;
ktab[key].args = SaveArgs (argc-2, ap+2);
} else Msg (0, "%s: unknown function \"%s\".", fn, ap[2]);
}
} else Msg (0, "%s: unknown keyword \"%s\".", fn, ap[0]);
}
fclose (f);
}
static Parse (fn, buf, args) char *fn, *buf, **args; {
register char *p = buf, **ap = args;
register delim, argc = 0;
argc = 0;
for (;;) {
while (*p && (*p == ' ' || *p == '\t')) ++p;
if (*p == '\0' || *p == '#')
return argc;
if (argc > MAXARGS-1)
Msg (0, "%s: too many tokens.", fn);
delim = 0;
if (*p == '"' || *p == '\'') {
delim = *p; *p = '\0'; ++p;
}
++argc;
*ap = p; ++ap;
while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
++p;
if (*p == '\0') {
if (delim)
Msg (0, "%s: Missing quote.", fn);
else
return argc;
}
*p++ = '\0';
}
}
static char **SaveArgs (argc, argv) register argc; register char **argv; {
register char **ap, **pp;
if ((pp = ap = (char **)malloc ((argc+1) * sizeof (char **))) == 0)
Msg (0, "Out of memory.");
while (argc--) {
if ((*pp = malloc (strlen (*argv)+1)) == 0)
Msg (0, "Out of memory.");
strcpy (*pp, *argv);
++pp; ++argv;
}
*pp = 0;
return ap;
}
static MakeNewEnv () {
register char **op, **np = NewEnv;
static char buf[MAXSTR];
if (strlen (SockName) > MAXSTR-5)
SockName = "?";
sprintf (buf, "STY=%s", SockName);
*np++ = buf;
*np++ = Term;
np += 2;
for (op = environ; *op; ++op) {
if (np == NewEnv + MAXARGS - 1)
break;
if (!IsSymbol (*op, "TERM") && !IsSymbol (*op, "TERMCAP")
&& !IsSymbol (*op, "STY"))
*np++ = *op;
}
*np = 0;
}
static IsSymbol (e, s) register char *e, *s; {
register char *p;
register n;
for (p = e; *p && *p != '='; ++p) ;
if (*p) {
*p = '\0';
n = strcmp (e, s);
*p = '=';
return n == 0;
}
return 0;
}
/*VARARGS2*/
Msg (err, fmt, p1, p2, p3, p4, p5, p6) char *fmt; {
char buf[1024];
register char *p = buf;
sprintf (p, fmt, p1, p2, p3, p4, p5, p6);
if (err) {
p += strlen (p);
if (err > 0 && err < sys_nerr)
sprintf (p, ": %s", sys_errlist[err]);
else
sprintf (p, ": Error %d", err);
}
if (HasWindow) {
MakeStatus (buf, curr);
} else {
printf ("%s\r\n", buf);
exit (1);
}
}
bclear (p, n) char *p; {
bcopy (blank, p, n);
}
static char *Filename (s) char *s; {
register char *p;
p = s + strlen (s) - 1;
while (p >= s && *p != '/') --p;
return ++p;
}
static IsNum (s, base) register char *s; register base; {
for (base += '0'; *s; ++s)
if (*s < '0' || *s > base)
return 0;
return 1;
}