386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Mon, 18 May 1992 03:27:09 +0000 (19:27 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Mon, 18 May 1992 03:27:09 +0000 (19:27 -0800)
Work on file usr/othersrc/public/screen-3.2/screen3.2/ansi.c
Work on file usr/othersrc/public/screen-3.2/screen3.2/ansi.h
Work on file usr/othersrc/public/screen-3.2/screen3.2/fileio.c
Work on file usr/othersrc/public/screen-3.2/screen3.2/patchlevel.h
Work on file usr/othersrc/public/screen-3.2/screen3.2/putenv.c
Work on file usr/othersrc/public/screen-3.2/screen3.2/screen.1

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/othersrc/public/screen-3.2/screen3.2/ansi.c [new file with mode: 0644]
usr/othersrc/public/screen-3.2/screen3.2/ansi.h [new file with mode: 0644]
usr/othersrc/public/screen-3.2/screen3.2/fileio.c [new file with mode: 0644]
usr/othersrc/public/screen-3.2/screen3.2/patchlevel.h [new file with mode: 0644]
usr/othersrc/public/screen-3.2/screen3.2/putenv.c [new file with mode: 0644]
usr/othersrc/public/screen-3.2/screen3.2/screen.1 [new file with mode: 0644]

diff --git a/usr/othersrc/public/screen-3.2/screen3.2/ansi.c b/usr/othersrc/public/screen-3.2/screen3.2/ansi.c
new file mode 100644 (file)
index 0000000..51284f1
--- /dev/null
@@ -0,0 +1,3500 @@
+/* Copyright (c) 1991
+ *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ * All rights reserved.  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 authors are not construed to be liable for any results of using the
+ * software, alterations are clearly marked as such, and this notice is
+ * not modified.
+ *
+ * Noteworthy contributors to screen's design and implementation:
+ *     Wayne Davison (davison@borland.com)
+ *     Patrick Wolfe (pat@kai.com, kailand!pat)
+ *     Bart Schaefer (schaefer@cse.ogi.edu)
+ *     Nathan Glasser (nathan@brokaw.lcs.mit.edu)
+ *     Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
+ *     Howard Chu (hyc@hanauma.jpl.nasa.gov)
+ *     Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
+ *     Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
+ *     Marc Boucher (marc@CAM.ORG)
+ *
+ ****************************************************************
+ */
+
+#ifndef lint
+  static char rcs_id[] = "$Id: ansi.c,v 1.2 92/02/03 02:27:30 jnweiger Exp $ FAU";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef BSDI
+#include <sys/signal.h>
+#endif /* BSDI */
+#include <fcntl.h>
+#include "config.h"
+#include "screen.h"
+#include "ansi.h"
+#include "extern.h"
+#ifndef sun /* we want to know about TIOCGWINSZ. jw. */
+# include <sys/ioctl.h>
+#endif
+
+extern char *getenv(), *tgetstr(), *tgoto();
+#ifndef __STDC__
+extern char *malloc();
+#endif
+
+extern struct win *fore;
+extern int ForeNum;
+extern force_vt, assume_LP;
+extern int BellDisplayed;
+extern int MsgMinWait;
+extern int all_norefresh;
+
+int TermcapROWS, TermcapCOLS;  /* defaults that we learned from termcap */
+int default_width, default_height;     /* width/height a new window will get */
+
+int maxwidth;
+
+int Z0width, Z1width;          /* widths for Z0/Z1 switching */
+
+char display_tty[MAXPATH];
+int screenwidth, screenheight; /* width/height of the screen */
+int screentop, screenbot;      /* scrollregion start/end */
+int screenx, screeny;          /* cursor position */
+char GlobalAttr;               /* current attributes */
+char GlobalCharset;            /* current font */
+int insert;                    /* insert mode */
+int keypad;                    /* application keypad */
+int flow = 1;                  /* flow control */
+
+int status;                    /* status is displayed */
+static int status_lastx, status_lasty;
+
+static int rows, cols;         /* window size of the curr window */
+
+int default_flow = -1, wrap = 1, default_monitor = 0; 
+int visual_bell = 0, termcapHS, use_hardstatus = 1;
+char *Termcap, *extra_incap, *extra_outcap;
+static int Termcaplen;
+char *blank, *null, *LastMsg;
+char Term[MAXSTR+5];   /* +5: "TERM=" */
+char screenterm[20] = "screen";
+char *Z0, *Z1;
+int ISO2022, HS;
+time_t TimeDisplayed, time();
+
+/*
+ * the termcap routines need this to work
+ */
+short ospeed;
+char *BC;
+char *UP;
+
+static void AddCap __P((char *));
+static void MakeString __P((char *, char *, int, char *));
+static int Special __P((int));
+static void DoESC __P((int, int ));
+static void DoCSI __P((int, int ));
+static void CPutStr __P((char *, int));
+static void SetChar __P(());
+static void StartString __P((enum string_t));
+static void AddChar __P((int ));
+static void PrintChar __P((int ));
+static void PrintFlush __P((void));
+static void KeypadMode __P((int));
+static void DesignateCharset __P((int, int ));
+static void MapCharset __P((int));
+static void SaveCursor __P((void));
+static void RestoreCursor __P((void));
+static void CountChars __P((int));
+static int CalcCost __P((char *));
+static int Rewrite __P((int, int, int, int));
+static void BackSpace __P((void));
+static void Return __P((void));
+static void LineFeed __P((int));
+static void ReverseLineFeed __P((void));
+static void InsertAChar __P((int));
+static void InsertChar __P((int));
+static void DeleteChar __P((int));
+static void DeleteLine __P((int));
+static void InsertLine __P((int));
+static void ScrollUpMap __P((int));
+static void ScrollDownMap __P((int));
+static void Scroll __P((char *, int, int, char *));
+static void ForwardTab __P((void));
+static void BackwardTab __P((void));
+static void ClearScreen __P((void));
+static void ClearFromBOS __P((void));
+static void ClearToEOS __P((void));
+static void ClearLine __P((void));
+static void ClearToEOL __P((void));
+static void ClearFromBOL __P((void));
+static void ClearInLine __P((int, int, int, int ));
+static void CursorRight __P(());
+static void CursorUp __P(());
+static void CursorDown __P(());
+static void CursorLeft __P(());
+static void ASetMode __P((int));
+static void SelectRendition __P((void));
+static void FillWithEs __P((void));
+static void RedisplayLine __P((char *, char *, char *, int, int, int ));
+static void FindAKA __P((void));
+static void SetCurr __P((struct win *));
+static void inpRedisplayLine __P((int, int, int, int));
+static void process_inp_input __P((char **, int *));
+static void AbortInp __P((void));
+static void AKAfin __P((char *, int));
+static void Colonfin __P((char *, int));
+static void RAW_PUTCHAR __P((int));
+static char *e_tgetstr __P((char *, char **));
+static int e_tgetflag __P((char *));
+static int e_tgetnum __P((char *));
+
+
+static char *tbuf, *tentry, *termname;
+static char *tp;
+static char *TI, *TE, *BL, *VB, *CR, *NL, *CL, *IS;
+char *WS;      /* used in ResizeScreen() */
+char *CE;      /* used in help.c */
+static char *CM, *US, *UE, *SO, *SE, *CD, *DO, *SR, *SF, *AL;
+static char *CS, *DL, *DC, *IC, *IM, *EI, *ND, *KS, *KE;
+static char *MB, *MD, *MH, *MR, *ME, *PO, *PF, *HO;
+static char *TS, *FS, *DS, *VI, *VE, *VS;
+static char *CDC, *CDL, *CAL, *CUP, *CDO, *CLE, *CRI, *CIC;
+static char *attrtab[NATTR];
+static AM, MS, COP;
+int LP;
+/*
+ * Do not confuse S0 (es-zero), E0 (e-zero) with SO (es-oh), PO (pe-oh),
+ * Z0 (z-zero), DO (de-oh)... :-)
+ */
+static char *C0, *S0, *E0;
+static char c0_tab[256];
+/*
+ */
+static screencap = 0;
+char *OldImage, *OldAttr, *OldFont;
+static struct win *curr;
+static display = 1;
+static StrCost;
+static UPcost, DOcost, LEcost, NDcost, CRcost, IMcost, EIcost, NLcost;
+static tcLineLen;
+static StatLen;
+static lp_missing = 0;
+
+int in_ovl;
+int ovl_blockfore;
+void (*ovl_process)();
+void (*ovl_RedisplayLine)();
+int (*ovl_Rewrite)();
+
+static char *KeyCaps[] =
+{
+  "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9",
+  "kb", "kd", "kh", "kl", "ko", "kr", "ku",
+  "K1", "K2", "K3", "K4", "K5",
+  "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", "l8", "l9"
+};
+#define NKEYCAPS ((int)(sizeof(KeyCaps)/sizeof(*KeyCaps)))
+static char *KeyCapsArr[NKEYCAPS];
+
+static char TermcapConst[] = "\\\n\
+\t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\
+\t:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\
+\t:do=^J:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\EM:\\\n\
+\t:le=^H:bl=^G:cr=^M:it#8:ho=\\E[H:nw=\\EE:ta=^I:is=\\E)0:xv:";
+
+void
+InitTermcap()
+{
+  register char *s;
+  int i;
+
+  screencap = 0;
+  if ((s = getenv("SCREENCAP")) != 0)
+    {
+      if ((Termcap = malloc(strlen(s) + 10)) != 0)
+       {
+         sprintf(Termcap, "TERMCAP=%s", s);
+         screencap = 1;
+       }
+    }
+  else
+    Termcap = malloc((unsigned) 1024);
+  Termcaplen = 0;
+  tbuf = malloc((unsigned) 1024);
+  tentry = tp = malloc((unsigned) 1024);
+  if (!(Termcap && tbuf && tentry))
+    Msg_nomem;
+  bzero(tbuf, 1024);
+  if ((termname = getenv("TERM")) == 0)
+    Msg(0, "No TERM in environment.");
+  debug1("InitTermcap: looking for tgetent('%s');\n", termname);
+  if (tgetent(tbuf, termname) != 1)
+    Msg(0, "Cannot find termcap entry for %s.", termname);
+  debug1("got it:\n%s\n",tbuf);
+#ifdef DEBUG
+  if (extra_incap)
+    debug1("Extra incap: %s\n", extra_incap);
+  if (extra_outcap)
+    debug1("Extra outcap: %s\n", extra_outcap);
+#endif
+
+  TermcapCOLS = TermcapROWS = 0;
+  if (s = getenv("COLUMNS"))
+    TermcapCOLS = atoi(s);
+  if (TermcapCOLS <= 0)
+    TermcapCOLS = e_tgetnum("co");
+  if (TermcapCOLS <= 0)
+    TermcapCOLS = 80;
+  if (s = getenv("LINES"))
+    TermcapROWS = atoi(s);
+  if (TermcapROWS <= 0)
+    TermcapROWS = e_tgetnum("li");
+  if (TermcapROWS <= 0)
+    TermcapROWS = 24;
+
+  if (e_tgetflag("hc"))
+    Msg(0, "You can't run screen on a hardcopy terminal.");
+  if (e_tgetflag("os"))
+    Msg(0, "You can't run screen on a terminal that overstrikes.");
+  if (e_tgetflag("ns"))
+    Msg(0, "Terminal must support scrolling.");
+  if (!(CL = e_tgetstr("cl", &tp)))
+    Msg(0, "Clear screen capability required.");
+  if (!(CM = e_tgetstr("cm", &tp)))
+    Msg(0, "Addressable cursor capability required.");
+  if (default_flow < 0)
+    default_flow = e_tgetflag("NF") ? FLOW_NOW * 0 : 
+                  e_tgetflag("xo") ? FLOW_NOW * 1 :
+                  FLOW_AUTOFLAG;
+  AM = e_tgetflag("am");
+  LP = assume_LP || (!extra_incap && !strncmp(termname, "vt", 2))
+                || !AM || e_tgetflag("LP") || e_tgetflag("xv");
+  COP = e_tgetflag("OP");
+  HO = e_tgetstr("ho", &tp);
+  TI = e_tgetstr("ti", &tp);
+  TE = e_tgetstr("te", &tp);
+  if (!(BL = e_tgetstr("bl", &tp)))
+    BL = "\007";
+  VB = e_tgetstr("vb", &tp);
+  if (!(BC = e_tgetstr("bc", &tp)))
+    {
+      if (e_tgetflag("bs"))
+       BC = "\b";
+      else
+       BC = e_tgetstr("le", &tp);
+    }
+  if (!(CR = e_tgetstr("cr", &tp)))
+    CR = "\r";
+  if (!(NL = e_tgetstr("nl", &tp)))
+    NL = "\n";
+  IS = e_tgetstr("is", &tp);
+  MS = 1;
+  if (e_tgetnum("sg") <= 0 && e_tgetnum("ug") <= 0)
+    {
+      MS = e_tgetflag("ms");
+      attrtab[ATTR_DI] = MH = e_tgetstr("mh", &tp);    /* Dim */
+      attrtab[ATTR_US] = US = e_tgetstr("us", &tp);    /* Underline */
+      attrtab[ATTR_BD] = MD = e_tgetstr("md", &tp);    /* Bold */
+      attrtab[ATTR_RV] = MR = e_tgetstr("mr", &tp);    /* Reverse */
+      attrtab[ATTR_SO] = SO = e_tgetstr("so", &tp);    /* Standout */
+      attrtab[ATTR_BL] = MB = e_tgetstr("mb", &tp);    /* Blinking */
+      ME = e_tgetstr("me", &tp);
+      SE = e_tgetstr("se", &tp);
+      UE = e_tgetstr("ue", &tp);
+      /*
+       * Does ME also reverse the effect of SO and/or US?  This is not
+       * clearly specified by the termcap manual. Anyway, we should at
+       * least look whether ME and SE/UE are equal:
+       */
+      if (UE && ((SE && strcmp(SE, UE) == 0) || (ME && strcmp(ME, UE) == 0)))
+       UE = 0;
+      if (SE && (ME && strcmp(ME, SE) == 0))
+       SE = 0;
+
+      /* Set up missing entries */
+      s = 0;
+      for (i = NATTR-1; i >= 0; i--)
+       if (attrtab[i])
+         s = attrtab[i];
+      for (i = 0; i < NATTR; i++)
+       {
+         if (attrtab[i] == 0)
+           attrtab[i] = s;
+         else
+           s = attrtab[i];
+       }
+    }
+  else
+    {
+      US = UE = SO = SE = MB = MD = MH = MR = ME = 0;
+      for (i = 0; i < NATTR; i++)
+       attrtab[i] = 0;
+    }
+  CE = e_tgetstr("ce", &tp);
+  CD = e_tgetstr("cd", &tp);
+  if (!(DO = e_tgetstr("do", &tp)))
+    DO = NL;
+  UP = e_tgetstr("up", &tp);
+  ND = e_tgetstr("nd", &tp);
+  SR = e_tgetstr("sr", &tp);
+  if (!(SF = e_tgetstr("sf", &tp)))
+    SF = NL;
+  AL = e_tgetstr("al", &tp);
+  DL = e_tgetstr("dl", &tp);
+  CS = e_tgetstr("cs", &tp);
+  DC = e_tgetstr("dc", &tp);
+  IC = e_tgetstr("ic", &tp);
+  CIC = e_tgetstr("IC", &tp);
+  CDC = e_tgetstr("DC", &tp);
+  CDL = e_tgetstr("DL", &tp);
+  CAL = e_tgetstr("AL", &tp);
+  CUP = e_tgetstr("UP", &tp);
+  CDO = e_tgetstr("DO", &tp);
+  CLE = e_tgetstr("LE", &tp);
+  CRI = e_tgetstr("RI", &tp);
+  IM = e_tgetstr("im", &tp);
+  EI = e_tgetstr("ei", &tp);
+  if (e_tgetflag("in"))
+    IC = IM = 0;
+  if (IC && IC[0] == '\0')
+    IC = 0;
+  if (CIC && CIC[0] == '\0')
+    CIC = 0;
+  if (IM && IM[0] == '\0')
+    IM = 0;
+  if (EI && EI[0] == '\0')
+    EI = 0;
+  if (EI == 0)
+    IM = 0;
+  if (IC && IM && strcmp(IC, IM) == 0)
+    IC = 0;
+  KS = e_tgetstr("ks", &tp);
+  KE = e_tgetstr("ke", &tp);
+  if (KE == 0)
+    KS = 0;
+  ISO2022 = e_tgetflag("G0");
+  if (ISO2022)
+    {
+      if ((S0 = e_tgetstr("S0", &tp)) == NULL)
+#ifdef TERMINFO
+       S0 = "\033(%p1%c";
+#else
+       S0 = "\033(%.";
+#endif
+      if ((E0 = e_tgetstr("E0", &tp)) == NULL)
+       E0 = "\033(B";
+      C0 = e_tgetstr("C0", &tp);
+    }
+  else if ((S0 = e_tgetstr("as", &tp)) != NULL
+        && (E0 = e_tgetstr("ae", &tp)) != NULL)
+    {
+      ISO2022 = 1;
+      C0 = e_tgetstr("ac", &tp);
+    }
+  else
+    {
+      S0 = E0 = "";
+      C0 = "g.h.i'j-k-l-m-n+o~p\"q-r-s_t+u+v+w+x|y<z>";
+    }
+  for (i = 0; i < 256; i++)
+    c0_tab[i] = i;
+  if (C0)
+    for (i = strlen(C0)&~1; i >= 0; i-=2)
+      c0_tab[C0[i]] = C0[i+1];
+  debug1("ISO2022 = %d\n", ISO2022);
+  /* WS changes the window size */
+  WS = e_tgetstr("WS", &tp);
+  VI = e_tgetstr("vi", &tp);
+  VE = e_tgetstr("ve", &tp);
+  VS = e_tgetstr("vs", &tp);
+  PO = e_tgetstr("po", &tp);
+  if (!(PF = e_tgetstr("pf", &tp)))
+    PO = 0;
+  debug2("terminal size is %d, %d (says TERMCAP)\n", TermcapCOLS, TermcapROWS);
+  /* Termcap fields Z0 & Z1 contain width-changing sequences. */
+  if ((Z0 = e_tgetstr("Z0", &tp)) != NULL
+      && (Z1 = e_tgetstr("Z1", &tp)) == NULL)
+    Z0 = NULL;
+
+  Z0width = 132;
+  Z1width = 80;
+
+  CheckScreenSize(0);
+  if ((HS = e_tgetflag("hs")) != 0)
+    {
+      debug("oy! we have a hardware status line, says termcap\n");
+      TS = e_tgetstr("ts", &tp);
+      FS = e_tgetstr("fs", &tp);
+      DS = e_tgetstr("ds", &tp);
+      if ((HS = e_tgetnum("ws")) <= 0)
+       HS = screenwidth;
+      if (!TS || !FS || !DS)
+       HS = 0;
+    }
+  termcapHS = HS;
+  if (!use_hardstatus)
+    HS = 0;
+
+  UPcost = CalcCost(UP);
+  DOcost = CalcCost(DO);
+  NLcost = CalcCost(NL);
+  LEcost = CalcCost(BC);
+  NDcost = CalcCost(ND);
+  CRcost = CalcCost(CR);
+  IMcost = CalcCost(IM);
+  EIcost = CalcCost(EI);
+  for (i = 0; i < NKEYCAPS; i++)
+    KeyCapsArr[i] = e_tgetstr(KeyCaps[i], &tp);
+  MakeTermcap(0);
+}
+
+/*
+ * if the adaptflag is on, we keep the size of this display, else
+ * we may try to restore our old window sizes.
+ */
+void
+InitTerm(adapt)
+int adapt;
+{
+  display = 1;
+  screentop = screenbot = -1;
+  PutStr(IS);
+  PutStr(TI);
+  if (IM && strcmp(IM, EI))
+    PutStr(EI);
+  insert = 0;
+  if (KS && strcmp(KS, KE))
+    PutStr(KE);
+  keypad = 0;
+  PutStr(E0);
+  GlobalCharset = ASCII;
+  ResizeScreen((struct win *)0);
+  ChangeScrollRegion(0, screenheight-1);
+  PutStr(CL);
+  screenx = screeny = 0;
+  fflush(stdout);
+  debug1("we %swant to adapt all our windows to the display\n", 
+        (adapt) ? "" : "don't ");
+  /* In case the size was changed by a init sequence */
+  CheckScreenSize((adapt) ? 2 : 0);
+}
+
+void
+FinitTerm()
+{
+  display = 1;
+  InsertMode(0);
+  KeypadMode(0);
+  ResizeScreen((struct win *)0);
+  ChangeScrollRegion(0, screenheight - 1);
+  SaveSetAttr(0, ASCII);
+  screenx = screeny = -1;
+  GotoPos(0, screenheight - 1);
+  PutStr(TE);
+  fflush(stdout);
+  if (Termcap) 
+    {
+      Free(Termcap);
+      debug("FinitTerm: old termcap freed\n");
+    }
+  if (tbuf) 
+    {
+      Free(tbuf);
+      debug("FinitTerm: old tbuf freed\n");
+    }
+  if (tentry) 
+    {
+      Free(tentry);
+      debug("FinitTerm: old tentry freed\n");
+    }
+}
+
+static void AddCap(s)
+char *s;
+{
+  register int n;
+
+  if (tcLineLen + (n = strlen(s)) > 55 && Termcaplen < 1024-4)
+    {
+      strcpy(Termcap + Termcaplen, "\\\n\t:");
+      Termcaplen += 4;
+      tcLineLen = 0;
+    }
+  if (Termcaplen + n < 1024)
+    {
+      strcpy(Termcap + Termcaplen, s);
+      Termcaplen += n;
+      tcLineLen += n;
+    }
+  else
+    Msg(0, "TERMCAP overflow - sorry.");
+}
+
+char *MakeTermcap(aflag)
+int aflag;
+{
+  char buf[1024];
+  register char *p, *cp, ch;
+  int i;
+
+  if (screencap)
+    {
+      sprintf(Term, "TERM=screen");
+      return Termcap;
+    }
+  if (screenterm == 0 || *screenterm == '\0')
+    {
+      debug("MakeTermcap sets screenterm=screen\n");
+      strcpy(screenterm, "screen");
+    }
+  for (;;)
+    {
+      sprintf(Term, "TERM=");
+      p = Term + 5;
+      if (!aflag && strlen(screenterm) + strlen(termname) < MAXSTR-1)
+       {
+         sprintf(p, "%s.%s", screenterm, termname);
+         if (tgetent(buf, p) == 1)
+           break;
+       }
+      if (screenwidth >= 132)
+       {
+         sprintf(p, "%s-w", screenterm);
+          if (tgetent(buf, p) == 1)
+           break;
+       }
+      sprintf(p, "%s", screenterm);
+      if (tgetent(buf, p) == 1)
+       break;
+      sprintf(p, "vt100");
+      break;
+    }
+  tcLineLen = 100;     /* Force NL */
+  sprintf(Termcap,
+         "TERMCAP=SC|%s|VT 100/ANSI X3.64 virtual terminal|", p);
+  Termcaplen = strlen(Termcap);
+  if (extra_outcap && *extra_outcap)
+    {
+      for (cp = extra_outcap; p = index(cp, ':'); cp = p)
+       {
+         ch = *++p;
+         *p = '\0';
+         AddCap(cp);
+         *p = ch;
+       }
+      tcLineLen = 100; /* Force NL */
+    }
+  if (Termcaplen + strlen(TermcapConst) < 1024)
+    {
+      strcpy(Termcap + Termcaplen, TermcapConst);
+      Termcaplen += strlen(TermcapConst);
+    }
+  sprintf(buf, "li#%d:co#%d:", screenheight, screenwidth);
+  AddCap(buf);
+  if ((force_vt && !COP) || LP || !AM)
+    AddCap("LP:");
+  else
+    AddCap("am:");
+  if (VB)
+    AddCap("vb=\\E[?5h\\E[?5l:");
+  if (US)
+    {
+      AddCap("us=\\E[4m:");
+      AddCap("ue=\\E[24m:");
+    }
+  if (SO)
+    {
+      AddCap("so=\\E[3m:");
+      AddCap("se=\\E[23m:");
+    }
+  if (MB)
+    AddCap("mb=\\E[5m:");
+  if (MD)
+    AddCap("md=\\E[1m:");
+  if (MH)
+    AddCap("mh=\\E[2m:");
+  if (MR)
+    AddCap("mr=\\E[7m:");
+  if (MB || MD || MH || MR)
+    AddCap("me=\\E[m:ms:");
+  if ((CS && SR) || AL || CAL || aflag)
+    {
+      AddCap("sr=\\EM:");
+      AddCap("al=\\E[L:");
+      AddCap("AL=\\E[%dL:");
+    }
+  else if (SR)
+    AddCap("sr=\\EM:");
+  if (CS || DL || CDL || aflag)
+    {
+      AddCap("dl=\\E[M:");
+      AddCap("DL=\\E[%dM:");
+    }
+  if (CS)
+    AddCap("cs=\\E[%i%d;%dr:");
+  if (DC || CDC || aflag)
+    {
+      AddCap("dc=\\E[P:");
+      AddCap("DC=\\E[%dP:");
+    }
+  if (CIC || IC || IM || aflag)
+    {
+      AddCap("im=\\E[4h:");
+      AddCap("ei=\\E[4l:");
+      AddCap("mi:");
+      AddCap("ic=\\E[@:");
+      AddCap("IC=\\E[%d@:");
+    }
+  if (KS)
+    AddCap("ks=\\E=:");
+  if (KE)
+    AddCap("ke=\\E>:");
+  if (ISO2022)
+    AddCap("G0:");
+  if (PO)
+    {
+      AddCap("po=\\E[5i:");
+      AddCap("pf=\\E[4i:");
+    }
+  if (Z0)
+    {
+      AddCap("Z0=\\E[?3h:");
+      AddCap("Z1=\\E[?3l:");
+    }
+  if (WS)
+    AddCap("WS=\\E[8;%d;%dt:");
+  for (i = 0; i < NKEYCAPS; i++)
+    {
+      if (KeyCapsArr[i] == 0)
+       continue;
+      MakeString(KeyCaps[i], buf, sizeof(buf), KeyCapsArr[i]);
+      AddCap(buf);
+    }
+  return Termcap;
+}
+
+static void MakeString(cap, buf, buflen, s)
+char *cap, *buf;
+int buflen;
+char *s;
+{
+  register char *p, *pmax;
+  register unsigned int c;
+
+  p = buf;
+  pmax = p + buflen - (3+4+2);
+  *p++ = *cap++;
+  *p++ = *cap;
+  *p++ = '=';
+  while ((c = *s++) && (p < pmax))
+    {
+      switch (c)
+       {
+       case '\033':
+         *p++ = '\\';
+         *p++ = 'E';
+         break;
+       case ':':
+         sprintf(p, "\\072");
+         p += 4;
+         break;
+       case '^':
+       case '\\':
+         *p++ = '\\';
+         *p++ = c;
+         break;
+       default:
+         if (c >= 200)
+           {
+             sprintf(p, "\\%03o", c & 0377);
+             p += 4;
+           }
+         else if (c < ' ')
+           {
+             *p++ = '^';
+             *p++ = c + '@';
+           }
+         else
+           *p++ = c;
+       }
+    }
+  *p++ = ':';
+  *p = '\0';
+}
+
+void
+Activate(norefresh)
+int norefresh;
+{
+  debug1("Activate(%d)\n", norefresh);
+  if (display)
+    RemoveStatus();
+  display = fore->active = 1;
+  ResizeScreen(fore);
+  SetCurr(fore);
+  debug3("Fore (%d) has size %dx%d", ForeNum, curr->width, curr->height);
+  debug1("(%d)\n", curr->histheight);
+  ChangeScrollRegion(curr->top, curr->bot);
+  KeypadMode(curr->keypad);
+  SetFlow(curr->flow & FLOW_NOW);
+  if (curr->monitor != MON_OFF)
+    curr->monitor = MON_ON;
+  curr->bell = BELL_OFF;
+  Redisplay(norefresh || all_norefresh);
+}
+
+void
+ResetScreen(p)
+register struct win *p;
+{
+  register int i;
+
+  p->wrap = wrap;
+  p->origin = 0;
+  p->insert = 0;
+  p->vbwait = 0;
+  p->keypad = 0;
+  p->top = 0;
+  p->bot = p->height - 1;
+  p->saved = 0;
+  p->LocalAttr = 0;
+  p->x = p->y = 0;
+  p->state = LIT;
+  p->StringType = NONE;
+  p->ss = 0;
+  p->LocalCharset = G0;
+  bzero(p->tabs, p->width);
+  for (i = 8; i < p->width; i += 8)
+    p->tabs[i] = 1;
+  for (i = G0; i <= G3; i++)
+    p->charsets[i] = ASCII;
+}
+
+void
+WriteString(wp, buf, len)
+struct win *wp;
+char *buf;
+int len;
+{
+  register int c, intermediate = 0;
+
+  if (!len)
+    return;
+  if (wp->logfp != NULL)
+    if ((int)fwrite(buf, len, 1, wp->logfp) < 1)
+      {
+       extern int errno;
+
+       Msg(errno, "Error writing logfile");
+       fclose(wp->logfp);
+       wp->logfp = NULL;
+      }
+  /*
+   * SetCurr() here may prevent output, as it may set display = 0
+   */
+  SetCurr(wp);
+  if (display)
+    {
+      if (!HS)
+       RemoveStatus();
+    }
+  else if (curr->monitor == MON_ON)
+    curr->monitor = MON_FOUND;
+
+  do
+    {
+      c = (unsigned char)*buf++;
+      if (c == '\0' || c == '\177')
+       continue;
+    NextChar:
+      switch (curr->state)
+       {
+       case PRIN:
+         switch (c)
+           {
+           case '\033':
+             curr->state = PRINESC;
+             break;
+           default:
+             PrintChar(c);
+           }
+         break;
+       case PRINESC:
+         switch (c)
+           {
+           case '[':
+             curr->state = PRINCSI;
+             break;
+           default:
+             PrintChar('\033');
+             PrintChar(c);
+             curr->state = PRIN;
+           }
+         break;
+       case PRINCSI:
+         switch (c)
+           {
+           case '4':
+             curr->state = PRIN4;
+             break;
+           default:
+             PrintChar('\033');
+             PrintChar('[');
+             PrintChar(c);
+             curr->state = PRIN;
+           }
+         break;
+       case PRIN4:
+         switch (c)
+           {
+           case 'i':
+             curr->state = LIT;
+             PrintFlush();
+             break;
+           default:
+             PrintChar('\033');
+             PrintChar('[');
+             PrintChar('4');
+             PrintChar(c);
+             curr->state = PRIN;
+           }
+         break;
+       case STRESC:
+         switch (c)
+           {
+           case '\\':
+             curr->state = LIT;
+             *(curr->stringp) = '\0';
+             switch (curr->StringType)
+               {
+               case PM:
+                 if (!display)
+                   break;
+                 MakeStatus(curr->string);
+                 if (!HS && status && len > 1)
+                   {
+                     curr->outlen = len - 1;
+                     bcopy(buf, curr->outbuf, curr->outlen);
+                     return;
+                   }
+                 break;
+               case DCS:
+                 if (display)
+                   printf("%s", curr->string);
+                 break;
+               case AKA:
+                 if (curr->akapos == 0 && !*curr->string)
+                   break;
+                 strncpy(curr->cmd + curr->akapos, curr->string, 20);
+                 if (!*curr->string)
+                   curr->autoaka = curr->y + 1;
+                 break;
+               default:
+                 break;
+               }
+             break;
+           default:
+             curr->state = ASTR;
+             AddChar('\033');
+             AddChar(c);
+           }
+         break;
+       case ASTR:
+         switch (c)
+           {
+           case '\0':
+             break;
+           case '\033':
+             curr->state = STRESC;
+             break;
+           default:
+             AddChar(c);
+           }
+         break;
+       case ESC:
+         switch (c)
+           {
+           case '[':
+             curr->NumArgs = 0;
+             intermediate = 0;
+             bzero((char *) curr->args, MAXARGS * sizeof(int));
+             curr->state = CSI;
+             break;
+           case ']':
+             StartString(OSC);
+             break;
+           case '_':
+             StartString(APC);
+             break;
+           case 'P':
+             StartString(DCS);
+             break;
+           case '^':
+             StartString(PM);
+             break;
+           case '"':
+           case 'k':
+             StartString(AKA);
+             break;
+           default:
+             if (Special(c))
+               break;
+             if (c >= ' ' && c <= '/')
+               intermediate = intermediate ? -1 : c;
+             else if (c >= '0' && c <= '~')
+               {
+                 DoESC(c, intermediate);
+                 curr->state = LIT;
+               }
+             else
+               {
+                 curr->state = LIT;
+                 goto NextChar;
+               }
+           }
+         break;
+       case CSI:
+         switch (c)
+           {
+           case '0':
+           case '1':
+           case '2':
+           case '3':
+           case '4':
+           case '5':
+           case '6':
+           case '7':
+           case '8':
+           case '9':
+             if (curr->NumArgs < MAXARGS)
+               {
+                 curr->args[curr->NumArgs] =
+                   10 * curr->args[curr->NumArgs] + c - '0';
+               }
+             break;
+           case ';':
+           case ':':
+             curr->NumArgs++;
+             break;
+           default:
+             if (Special(c))
+               break;
+             if (c >= '@' && c <= '~')
+               {
+                 curr->NumArgs++;
+                 DoCSI(c, intermediate);
+                 if (curr->state != PRIN)
+                   curr->state = LIT;
+               }
+             else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?'))
+               intermediate = intermediate ? -1 : c;
+             else
+               {
+                 curr->state = LIT;
+                 goto NextChar;
+               }
+           }
+         break;
+       case LIT:
+       default:
+         if (!Special(c))
+           {
+             if (c == '\033')
+               {
+                 intermediate = 0;
+                 curr->state = ESC;
+                 if (display && lp_missing && (CIC || IC || IM))
+                   {
+                     RedisplayLine(blank, null, null, screenbot,
+                                   cols - 2, cols - 1);
+                     GotoPos(curr->x, curr->y);
+                   }
+                 if (curr->autoaka < 0)
+                   curr->autoaka = 0;
+               }
+             else if (c < ' ')
+               break;
+             else
+               {
+                 NewRendition(curr->LocalAttr);
+                 NewCharset(curr->charsets[(curr->ss) ? curr->ss :
+                                            curr->LocalCharset]);
+                 if (curr->x < cols - 1)
+                   {
+                     if (curr->insert)
+                       InsertAChar(c);
+                     else
+                       {
+                         if (display)
+                           PUTCHAR(c);
+                         SetChar(c);
+                       }
+                     curr->x++;
+                   }
+                 else if (curr->x == cols - 1)
+                   {
+                     if (curr->wrap && (LP || !force_vt || COP))
+                       {
+                         if (display)
+                           RAW_PUTCHAR(c);
+                         SetChar(c);
+                         if (AM && !LP)
+                           {
+                             curr->x = 0; /* terminal auto-wrapped */
+                             LineFeed(0);
+                           }
+                         else
+                           curr->x++;
+                       }
+                     else
+                       {
+                         if (display)
+                           {
+                             if (LP || curr->y != screenbot)
+                               {
+                                 RAW_PUTCHAR(c);
+                                 GotoPos(curr->x, curr->y);
+                               }
+                             else
+                               CheckLP(c);
+                           }
+                         SetChar(c);
+                         if (curr->wrap)
+                           curr->x++;
+                       }
+                   }
+                 else
+                   {
+                     LineFeed(2); /* cr+lf, handle LP */
+                     if (curr->insert)
+                       InsertAChar(c);
+                     else
+                       {
+                         if (display)
+                           PUTCHAR(c);
+                         SetChar(c);
+                       }
+                     curr->x = 1;
+                   }
+                 if (curr->ss)
+                   {
+                     NewCharset(curr->charsets[curr->LocalCharset]);
+                     curr->ss = 0;
+                   }
+               }
+           }
+       }
+    } while (--len);
+  curr->outlen = 0;
+  if (curr->state == PRIN)
+    PrintFlush();
+}
+
+static int Special(c)
+register int c;
+{
+  switch (c)
+    {
+    case '\b':
+      BackSpace();
+      return 1;
+    case '\r':
+      Return();
+      return 1;
+    case '\n':
+      if (curr->autoaka)
+       FindAKA();
+      LineFeed(1);
+      return 1;
+    case '\007':
+      if (!visual_bell)
+       PutStr(BL);
+      else
+       {
+         if (!VB)
+           curr->bell = BELL_VISUAL;
+         else
+           PutStr(VB);
+       }
+      if (!display)
+       curr->bell = BELL_ON;
+      return 1;
+    case '\t':
+      ForwardTab();
+      return 1;
+    case '\017':               /* SI */
+      MapCharset(G0);
+      return 1;
+    case '\016':               /* SO */
+      MapCharset(G1);
+      return 1;
+    }
+  return 0;
+}
+
+static void DoESC(c, intermediate)
+int c, intermediate;
+{
+  switch (intermediate)
+    {
+    case 0:
+      switch (c)
+       {
+       case 'E':
+         LineFeed(2);
+         break;
+       case 'D':
+         LineFeed(1);
+         break;
+       case 'M':
+         ReverseLineFeed();
+         break;
+       case 'H':
+         curr->tabs[curr->x] = 1;
+         break;
+       case 'Z':               /* jph: Identify as VT100 */
+         Report(curr, "\033[?%d;%dc", 1, 2);
+         break;
+       case '7':
+         SaveCursor();
+         break;
+       case '8':
+         RestoreCursor();
+         break;
+       case 'c':
+         ClearScreen();
+         ResetScreen(curr);
+         NewRendition(0);
+         NewCharset(ASCII);
+         InsertMode(0);
+         KeypadMode(0);
+         ChangeScrollRegion(0, rows-1);
+         break;
+       case '=':
+         KeypadMode(curr->keypad = 1);
+#if !defined(TIOCPKT) || defined(sgi)
+         NewAutoFlow(curr, 0);
+#endif /* !TIOCPKT || sgi */
+         break;
+       case '>':
+         KeypadMode(curr->keypad = 0);
+#if !defined(TIOCPKT) || defined(sgi)
+         NewAutoFlow(curr, 1);
+#endif /* !TIOCPKT || sgi */
+         break;
+       case 'n':               /* LS2 */
+         MapCharset(G2);
+         break;
+       case 'o':               /* LS3 */
+         MapCharset(G3);
+         break;
+       case 'N':               /* SS2 */
+         if (curr->charsets[curr->LocalCharset] != curr->charsets[G2])
+           curr->ss = G2;
+         else
+           curr->ss = 0;
+         break;
+       case 'O':               /* SS3 */
+         if (curr->charsets[curr->LocalCharset] != curr->charsets[G3])
+           curr->ss = G3;
+         else
+           curr->ss = 0;
+         break;
+       }
+      break;
+    case '#':
+      switch (c)
+       {
+       case '8':
+         FillWithEs();
+         break;
+       }
+      break;
+    case '(':
+      DesignateCharset(c, G0);
+      break;
+    case ')':
+      DesignateCharset(c, G1);
+      break;
+    case '*':
+      DesignateCharset(c, G2);
+      break;
+    case '+':
+      DesignateCharset(c, G3);
+      break;
+    }
+}
+
+static void DoCSI(c, intermediate)
+int c, intermediate;
+{
+  register int i, a1 = curr->args[0], a2 = curr->args[1];
+
+  if (curr->NumArgs > MAXARGS)
+    curr->NumArgs = MAXARGS;
+  switch (intermediate)
+    {
+    case 0:
+      switch (c)
+       {
+       case 'H':
+       case 'f':
+         if (a1 < 1)
+           a1 = 1;
+         if (curr->origin)
+           a1 += curr->top;
+         if (a1 > rows)
+           a1 = rows;
+         if (a2 < 1)
+           a2 = 1;
+         if (a2 > cols)
+           a2 = cols;
+         GotoPos(--a2, --a1);
+         curr->x = a2;
+         curr->y = a1;
+         if (curr->autoaka)
+           curr->autoaka = a1 + 1;
+         break;
+       case 'J':
+         if (a1 < 0 || a1 > 2)
+           a1 = 0;
+         switch (a1)
+           {
+           case 0:
+             ClearToEOS();
+             break;
+           case 1:
+             ClearFromBOS();
+             break;
+           case 2:
+             ClearScreen();
+             GotoPos(curr->x, curr->y);
+             break;
+           }
+         break;
+       case 'K':
+         if (a1 < 0 || a1 > 2)
+           a1 %= 3;
+         switch (a1)
+           {
+           case 0:
+             ClearToEOL();
+             break;
+           case 1:
+             ClearFromBOL();
+             break;
+           case 2:
+             ClearLine();
+             break;
+           }
+         break;
+       case 'A':
+         CursorUp(a1 ? a1 : 1);
+         break;
+       case 'B':
+         CursorDown(a1 ? a1 : 1);
+         break;
+       case 'C':
+         CursorRight(a1 ? a1 : 1);
+         break;
+       case 'D':
+         CursorLeft(a1 ? a1 : 1);
+         break;
+       case 'm':
+         SelectRendition();
+         break;
+       case 'g':
+         if (a1 == 0)
+           curr->tabs[curr->x] = 0;
+         else if (a1 == 3)
+           bzero(curr->tabs, cols);
+         break;
+       case 'r':
+         if (!a1)
+           a1 = 1;
+         if (!a2)
+           a2 = rows;
+         if (a1 < 1 || a2 > rows || a1 >= a2)
+           break;
+         curr->top = a1 - 1;
+         curr->bot = a2 - 1;
+         ChangeScrollRegion(curr->top, curr->bot);
+         if (curr->origin)
+           {
+             GotoPos(0, curr->top);
+             curr->y = curr->top;
+             curr->x = 0;
+           }
+         else
+           {
+             GotoPos(0, 0);
+             curr->y = curr->x = 0;
+           }
+         break;
+       case 's':
+         SaveCursor();
+         break;
+       case 't':
+         if (a1 != 8)
+           break;
+         a1 = curr->args[2];
+         if (a1 < 1)
+           a1 = curr->width;
+         if (a2 < 1)
+           a2 = curr->height;
+         if (WS == NULL)
+           {
+             a2 = curr->height;
+             if (Z0 == NULL || (a1 != Z0width && a1 != Z1width))
+               a1 = curr->width;
+           }
+         if (a1 == curr->width && a2 == curr->height)
+           break;
+          ChangeWindowSize(curr, a1, a2);
+         SetCurr(curr);
+         if (display)
+           Activate(0);
+         break;
+       case 'u':
+         RestoreCursor();
+         break;
+       case 'I':
+         if (!a1)
+           a1 = 1;
+         while (a1--)
+           ForwardTab();
+         break;
+       case 'Z':
+         if (!a1)
+           a1 = 1;
+         while (a1--)
+           BackwardTab();
+         break;
+       case 'L':
+         InsertLine(a1 ? a1 : 1);
+         break;
+       case 'M':
+         DeleteLine(a1 ? a1 : 1);
+         break;
+       case 'P':
+         DeleteChar(a1 ? a1 : 1);
+         break;
+       case '@':
+         InsertChar(a1 ? a1 : 1);
+         break;
+       case 'h':
+         ASetMode(1);
+         break;
+       case 'l':
+         ASetMode(0);
+         break;
+       case 'i':
+         if (PO && a1 == 5)
+           {
+             curr->stringp = curr->string;
+             curr->state = PRIN;
+           }
+         break;
+       case 'n':
+         if (a1 == 6)          /* Report cursor position */
+           Report(curr, "\033[%d;%dR", curr->y + 1, curr->x + 1);
+         break;
+       case 'c':               /* Identify as VT100 */
+         Report(curr, "\033[?%d;%dc", 1, 2);
+         break;
+       }
+      break;
+    case '?':
+      debug2("\\E[?%d%c\n",a1,c);
+      if (c != 'h' && c != 'l')
+       break;
+      i = (c == 'h');
+      switch (a1)
+       {
+       case 3:
+         i = (i ? Z0width : Z1width);
+         if ((Z0 || WS) && curr->width != i)
+           {
+              ChangeWindowSize(curr, i, curr->height);
+             SetCurr(curr);
+             if (display)
+               Activate(0);
+           }
+         break;
+       case 5:
+         if (i)
+           curr->vbwait = 1;
+         else
+           {
+             if (curr->vbwait)
+               PutStr(VB);
+             curr->vbwait = 0;
+           }
+         break;
+       case 6:
+         if ((curr->origin = i) != 0)
+           {
+             GotoPos(0, curr->top);
+             curr->y = curr->top;
+             curr->x = 0;
+           }
+         else
+           {
+             GotoPos(0, 0);
+             curr->y = curr->x = 0;
+           }
+         break;
+       case 7:
+         curr->wrap = i;
+         break;
+       case 35:
+         debug1("Cursor %svisible\n", i?"in":"");
+         curr->cursor_invisible = i;
+         break;
+       }
+      break;
+    }
+}
+
+void
+INSERTCHAR(c)
+int c;
+{
+  if (!insert && (IC || CIC))
+    {
+      if (IC)
+        PutStr(IC);
+      else
+        CPutStr(CIC, 1);
+      RAW_PUTCHAR(c);
+      return;
+    }
+  InsertMode(1);
+  if (insert)
+    RAW_PUTCHAR(c);
+  else
+    RefreshLine(screeny, screenx, screenwidth-1);
+}
+
+void
+PUTCHAR(c)
+int c;
+{
+  if (insert)
+    InsertMode(0);
+  RAW_PUTCHAR(c);
+}
+
+/*
+ * RAW_PUTCHAR() is for all text that will be displayed.
+ * NOTE, that charset Nr. 0 has a conversion table, but c1, c2, ... don't.
+ */
+
+static void
+RAW_PUTCHAR(c)
+int c;
+{
+  if (GlobalCharset == '0')
+    putchar(c0_tab[c]);
+  else
+    putchar(c);
+  if (screenx < screenwidth - 1)
+    screenx++;
+  else
+    {
+      screenx++;
+      if ((AM && !LP) || screenx > screenwidth)
+       {
+         screenx -= screenwidth;
+         if (screeny < screenheight-1 && screeny != screenbot)
+           screeny++;
+       }
+    }
+}
+
+void
+PutChar(c)
+int c;
+{
+  /* this PutChar for ESC-sequences only */
+  putchar(c);
+}
+
+void
+PutStr(s)
+char *s;
+{
+  if (display && s)
+    tputs(s, 1, PutChar);
+}
+
+static void CPutStr(s, c)
+char *s;
+int c;
+{
+  if (display && s)
+    tputs(tgoto(s, 0, c), 1, PutChar);
+}
+
+static void SetChar(c)
+register int c;
+{
+  register struct win *p = curr;
+
+  p->image[p->y][p->x] = c;
+  p->attr[p->y][p->x] = p->LocalAttr;
+  p->font[p->y][p->x] = p->charsets[p->ss ? p->ss : p->LocalCharset];
+}
+
+static void StartString(type)
+enum string_t type;
+{
+  curr->StringType = type;
+  curr->stringp = curr->string;
+  curr->state = ASTR;
+}
+
+static void AddChar(c)
+int c;
+{
+  if (curr->stringp >= curr->string + MAXSTR - 1)
+    curr->state = LIT;
+  else
+    *(curr->stringp)++ = c;
+}
+
+static void PrintChar(c)
+int c;
+{
+  if (curr->stringp >= curr->string + MAXSTR - 1)
+    PrintFlush();
+  *(curr->stringp)++ = c;
+}
+
+static void PrintFlush()
+{
+  if (curr->stringp > curr->string)
+    {
+      tputs(PO, 1, PutChar);
+      (void) fflush(stdout);
+      (void) write(1, curr->string, curr->stringp - curr->string);
+      tputs(PF, 1, PutChar);
+      (void) fflush(stdout);
+      curr->stringp = curr->string;
+    }
+}
+
+/* Insert mode is a toggle on some terminals, so we need this hack:
+ */
+void
+InsertMode(on)
+int on;
+{
+  if (display && on != insert && IM)
+    {
+      insert = on;
+      if (insert)
+       PutStr(IM);
+      else
+       PutStr(EI);
+    }
+}
+
+/* ...and maybe keypad application mode is a toggle, too:
+ */
+static void KeypadMode(on)
+int on;
+{
+  if (display && keypad != on && KS)
+    {
+      keypad = on;
+      if (keypad)
+       PutStr(KS);
+      else
+       PutStr(KE);
+    }
+}
+
+void
+NewAutoFlow(win, on)
+struct win *win;
+int on;
+{
+  debug1("NewAutoFlow: %d\n", on);
+  SetCurr(win);
+  if (win->flow & FLOW_AUTOFLAG)
+    win->flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on;
+  else
+    win->flow = (win->flow & ~FLOW_AUTO) | FLOW_AUTO * on;
+  if (display)
+    SetFlow(win->flow & FLOW_NOW);
+}
+
+static void DesignateCharset(c, n)
+int c, n;
+{
+  curr->ss = 0;
+  if (c == 'B')
+    c = ASCII;
+  if (curr->charsets[n] != c)
+    {
+      curr->charsets[n] = c;
+      if (curr->LocalCharset == n)
+       NewCharset(c);
+    }
+}
+
+static void MapCharset(n)
+int n;
+{
+  curr->ss = 0;
+  if (curr->LocalCharset != n)
+    {
+      curr->LocalCharset = n;
+      NewCharset(curr->charsets[n]);
+    }
+}
+
+void
+NewCharset(new)
+int new;
+{
+  if (!display || GlobalCharset == new)
+    return;
+  GlobalCharset = new;
+  if (new == ASCII)
+    PutStr(E0);
+  else
+    CPutStr(S0, new);
+}
+
+static void SaveCursor()
+{
+  curr->saved = 1;
+  curr->Saved_x = curr->x;
+  curr->Saved_y = curr->y;
+  curr->SavedLocalAttr = curr->LocalAttr;
+  curr->SavedLocalCharset = curr->LocalCharset;
+  bcopy((char *) curr->charsets, (char *) curr->SavedCharsets,
+       4 * sizeof(int));
+}
+
+static void RestoreCursor()
+{
+  if (curr->saved)
+    {
+      GotoPos(curr->Saved_x, curr->Saved_y);
+      curr->x = curr->Saved_x;
+      curr->y = curr->Saved_y;
+      curr->LocalAttr = curr->SavedLocalAttr;
+      NewRendition(curr->LocalAttr);
+      bcopy((char *) curr->SavedCharsets, (char *) curr->charsets,
+           4 * sizeof(int));
+      curr->LocalCharset = curr->SavedLocalCharset;
+      NewCharset(curr->charsets[curr->LocalCharset]);
+    }
+}
+
+/*ARGSUSED*/
+static void CountChars(c)
+int c;
+{
+  StrCost++;
+}
+
+static int CalcCost(s)
+register char *s;
+{
+  if (s)
+    {
+      StrCost = 0;
+      tputs(s, 1, CountChars);
+      return StrCost;
+    }
+  else
+    return EXPENSIVE;
+}
+
+void
+GotoPos(x2, y2)
+int x2, y2;
+{
+  register int dy, dx, x1, y1;
+  register int costx, costy;
+  register int m;
+  register char *s;
+  int CMcost;
+  enum move_t xm = M_NONE, ym = M_NONE;
+
+  if (!display)
+    return;
+
+  x1 = screenx;
+  y1 = screeny;
+
+  if (x1 == screenwidth)
+    if (LP && AM)
+      x1 = -1;         /* don't know how the terminal treats this */
+    else
+      x1--;
+  if (x2 == screenwidth)
+    x2--;
+  dx = x2 - x1;
+  dy = y2 - y1;
+  if (dy == 0 && dx == 0)
+    {
+      return;
+    }
+  if (!MS && GlobalAttr)       /* Safe to move in SO mode ? */
+    NewRendition(0);
+  if (y1 < 0                   /* don't know the y position */
+      || (y2 > screenbot && y1 <= screenbot)   /* have to cross border */
+      || (y2 < screentop && y1 >= screentop))  /* of scrollregion ?    */
+    {
+    DoCM:
+      if (HO && !x2 && !y2)
+        PutStr(HO);
+      else
+        PutStr(tgoto(CM, x2, y2));
+      screenx = x2;
+      screeny = y2;
+      return;
+    }
+  /* Calculate CMcost */
+  if (HO && !x2 && !y2)
+    s = HO;
+  else
+    s = tgoto(CM, x2, y2);
+  CMcost = CalcCost(s);
+
+  /* Calculate the cost to move the cursor to the right x position */
+  costx = EXPENSIVE;
+  if (x1 >= 0) /* relativ x positioning only if we know where we are */
+    {
+      if (dx > 0)
+       {
+         if (CRI && (dx > 1 || !ND))
+           {
+             costx = CalcCost(tgoto(CRI, 0, dx));
+             xm = M_CRI;
+           }
+         if ((m = NDcost * dx) < costx)
+           {
+             costx = m;
+             xm = M_RI;
+           }
+         /* Speedup: dx <= Rewrite() */
+         if (dx < costx && (m = Rewrite(y1, x1, x2, 0)) < costx)
+           {
+             costx = m;
+             xm = M_RW;
+           }
+       }
+      else if (dx < 0)
+       {
+         if (CLE && (dx < -1 || !BC))
+           {
+             costx = CalcCost(tgoto(CLE, 0, -dx));
+             xm = M_CLE;
+           }
+         if ((m = -dx * LEcost) < costx)
+           {
+             costx = m;
+             xm = M_LE;
+           }
+       }
+      else
+       costx = 0;
+    }
+  /* Speedup: Rewrite() >= x2 */
+  if (x2 + CRcost < costx && (m = Rewrite(y1, 0, x2, 0) + CRcost) < costx)
+    {
+      costx = m;
+      xm = M_CR;
+    }
+
+  /* Check if it is already cheaper to do CM */
+  if (costx >= CMcost)
+    goto DoCM;
+
+  /* Calculate the cost to move the cursor to the right y position */
+  costy = EXPENSIVE;
+  if (dy > 0)
+    {
+      if (CDO && dy > 1)       /* DO & NL are always != 0 */
+       {
+         costy = CalcCost(tgoto(CDO, 0, dy));
+         ym = M_CDO;
+       }
+      if ((m = dy * ((x2 == 0) ? NLcost : DOcost)) < costy)
+       {
+         costy = m;
+         ym = M_DO;
+       }
+    }
+  else if (dy < 0)
+    {
+      if (CUP && (dy < -1 || !UP))
+       {
+         costy = CalcCost(tgoto(CUP, 0, -dy));
+         ym = M_CUP;
+       }
+      if ((m = -dy * UPcost) < costy)
+       {
+         costy = m;
+         ym = M_UP;
+       }
+    }
+  else
+    costy = 0;
+
+  /* Finally check if it is cheaper to do CM */
+  if (costx + costy >= CMcost)
+    goto DoCM;
+
+  switch (xm)
+    {
+    case M_LE:
+      while (dx++ < 0)
+       PutStr(BC);
+      break;
+    case M_CLE:
+      CPutStr(CLE, -dx);
+      break;
+    case M_RI:
+      while (dx-- > 0)
+       PutStr(ND);
+      break;
+    case M_CRI:
+      CPutStr(CRI, dx);
+      break;
+    case M_CR:
+      PutStr(CR);
+      screenx = 0;
+      x1 = 0;
+      /* FALLTHROUGH */
+    case M_RW:
+      if (x1 < x2)
+       (void) Rewrite(y1, x1, x2, 1);
+      break;
+    default:
+      break;
+    }
+  switch (ym)
+    {
+    case M_UP:
+      while (dy++ < 0)
+       PutStr(UP);
+      break;
+    case M_CUP:
+      CPutStr(CUP, -dy);
+      break;
+    case M_DO:
+      s =  (x2 == 0) ? NL : DO;
+      while (dy-- > 0)
+       PutStr(s);
+      break;
+    case M_CDO:
+      CPutStr(CDO, dy);
+      break;
+    default:
+      break;
+    }
+  screenx = x2;
+  screeny = y2;
+}
+
+static int
+Rewrite(y, x1, x2, doit)
+int y, x1, x2, doit;
+{
+  register int cost, dx;
+  register char *p, *f, *i;
+
+  if (x1 == x2)
+    return(0);
+  if (in_ovl)
+    {
+      if (ovl_Rewrite == 0)
+        return EXPENSIVE;
+      else
+        return ((*ovl_Rewrite)(y, x1, x2, doit));
+    }
+  dx = x2 - x1;
+  if (doit)
+    {
+      i = curr->image[y] + x1;
+      while (dx-- > 0)
+       PUTCHAR(*i++);
+      return(0);
+    }
+  p = curr->attr[y] + x1;
+  f = curr->font[y] + x1;
+
+  cost = dx = x2 - x1;
+  if (insert)
+    cost += EIcost + IMcost;
+  while(dx-- > 0)
+    {
+      if (*p++ != GlobalAttr || *f++ != GlobalCharset)
+       return EXPENSIVE;
+    }
+  return cost;
+}
+
+static void BackSpace()
+{
+  if (curr->x > 0)
+    {
+      curr->x--;
+    }
+  else if (curr->wrap && curr->y > 0)
+    {
+      curr->x = cols - 1;
+      curr->y--;
+    }
+  if (display)
+    GotoPos(curr->x, curr->y);
+}
+
+static void Return()
+{
+  if (curr->x > 0)
+    {
+      curr->x = 0;
+      if (display)
+        GotoPos(curr->x, curr->y);
+    }
+}
+
+static void LineFeed(out_mode)
+int out_mode;
+{
+  /* out_mode: 0=no-output lf, 1=lf, 2=cr+lf */
+  if (out_mode == 2)
+    curr->x = 0;
+  if (curr->y != curr->bot)            /* Don't scroll */
+    {
+      if (curr->y < rows-1)
+       curr->y++;
+      if (out_mode && display)
+       GotoPos(curr->x, curr->y);
+      return;
+    }
+  ScrollUpMap(1);
+  if (curr->autoaka > 1)
+    curr->autoaka--;
+  if (out_mode && display)
+    {
+      ScrollRegion(curr->top, curr->bot, 1);
+      GotoPos(curr->x, curr->y);
+    }
+}
+
+static void ReverseLineFeed()
+{
+  if (curr->y == curr->top)
+    {
+      ScrollDownMap(1);
+      if (!display)
+       return;
+      ScrollRegion(curr->top, curr->bot, -1);
+      GotoPos(curr->x, curr->y);
+    }
+  else if (curr->y > 0)
+    CursorUp(1);
+}
+
+static void InsertAChar(c)
+int c;
+{
+  register int y = curr->y, x = curr->x;
+
+  if (x == cols)
+    x--;
+  bcopy(curr->image[y], OldImage, cols);
+  bcopy(curr->attr[y], OldAttr, cols);
+  bcopy(curr->font[y], OldFont, cols);
+  bcopy(curr->image[y] + x, curr->image[y] + x + 1, cols - x - 1);
+  bcopy(curr->attr[y] + x, curr->attr[y] + x + 1, cols - x - 1);
+  bcopy(curr->font[y] + x, curr->font[y] + x + 1, cols - x - 1);
+  SetChar(c);
+  if (!display)
+    return;
+  if (CIC || IC || IM)
+    {
+      InsertMode(curr->insert);
+      INSERTCHAR(c);
+      if (y == screenbot)
+       lp_missing = 0;
+    }
+  else
+    {
+      RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1);
+      GotoPos(++x, y);
+    }
+}
+
+static void InsertChar(n)
+int n;
+{
+  register int i, y = curr->y, x = curr->x;
+
+  if (n <= 0)
+    return;
+  /*
+   * The termcap manual states that only one of IM and IC is
+   * to be defined unless the terminal needs both sequences.
+   * We don't like this because we think that there may be cases
+   * where it is preferable to send IC instead of IM/EI.
+   * The hack is to ignore the IC sequence if we are already
+   * in insert mode, so that programs which follow the termcap
+   * guidelines still work. (I don't believe that there are
+   * terminals which need IC in the insert mode. Why switch to
+   * insert mode if you must send IC before every character ?)
+   */
+  if (curr->insert)
+    return;
+  if (x == cols)
+    --x;
+  bcopy(curr->image[y], OldImage, cols);
+  bcopy(curr->attr[y], OldAttr, cols);
+  bcopy(curr->font[y], OldFont, cols);
+  if (n > cols - x)
+    n = cols - x;
+  bcopy(curr->image[y] + x, curr->image[y] + x + n, cols - x - n);
+  bcopy(curr->attr[y] + x, curr->attr[y] + x + n, cols - x - n);
+  bcopy(curr->font[y] + x, curr->font[y] + x + n, cols - x - n);
+  ClearInLine(0, y, x, x + n - 1);
+  if (!display)
+    return;
+  if (IC || CIC || IM)
+    {
+      if (y == screenbot)
+       lp_missing = 0;
+      if (!insert)
+       {
+         if (n == 1 && IC)
+           {
+             PutStr(IC);
+             return;
+            }
+         if (CIC)
+           {
+             CPutStr(CIC, n);
+             return;
+            }
+       }
+      InsertMode(1);
+      for (i = n; i--; )
+       INSERTCHAR(' ');
+      GotoPos(x, y);
+    }
+  else
+    {
+      RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1);
+      GotoPos(x, y);
+    }
+}
+
+static void DeleteChar(n)
+int n;
+{
+  register int i, y = curr->y, x = curr->x;
+
+  if (x == cols)
+    --x;
+  bcopy(curr->image[y], OldImage, cols);
+  bcopy(curr->attr[y], OldAttr, cols);
+  bcopy(curr->font[y], OldFont, cols);
+  if (n > cols - x)
+    n = cols - x;
+  bcopy(curr->image[y] + x + n, curr->image[y] + x, cols - x - n);
+  bcopy(curr->attr[y] + x + n, curr->attr[y] + x, cols - x - n);
+  bcopy(curr->font[y] + x + n, curr->font[y] + x, cols - x - n);
+  ClearInLine(0, y, cols - n, cols - 1);
+  if (!display)
+    return;
+  if (CDC && !(n == 1 && DC))
+    {
+      CPutStr(CDC, n);
+      if (lp_missing && y == screenbot)
+       {
+         FixLP(cols - 1 - n, y);
+          GotoPos(x, y);
+       }
+    }
+  else if (DC)
+    {
+      for (i = n; i; i--)
+       PutStr(DC);
+      if (lp_missing && y == screenbot)
+       {
+         FixLP(cols - 1 - n, y);
+          GotoPos(x, y);
+       }
+    }
+  else
+    {
+      RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1);
+      GotoPos(x, y);
+    }
+}
+
+static void DeleteLine(n)
+int n;
+{
+  register int old = curr->top;
+  
+  if (curr->y < curr->top || curr->y > curr->bot)
+    return;
+  if (n > curr->bot - curr->y + 1)
+    n = curr->bot - curr->y + 1;
+  curr->top = curr->y;
+  ScrollUpMap(n);
+  curr->top = old;
+  if (!display)
+    return;
+  ScrollRegion(curr->y, curr->bot, n);
+  GotoPos(curr->x, curr->y);
+}
+
+static void InsertLine(n)
+int n;
+{
+  register int old = curr->top;
+
+  if (curr->y < curr->top || curr->y > curr->bot)
+    return;
+  if (n > curr->bot - curr->y + 1)
+    n = curr->bot - curr->y + 1;
+  curr->top = curr->y;
+  ScrollDownMap(n);
+  curr->top = old;
+  if (!display)
+    return;
+  ScrollRegion(curr->y, curr->bot, -n);
+  GotoPos(curr->x, curr->y);
+}
+
+void
+ScrollRegion(ys, ye, n)
+int ys, ye, n;
+{
+  int i;
+  int up;
+  int oldtop, oldbot;
+  int alok, dlok, aldlfaster;
+  int missy = 0;
+
+  if (n == 0)
+    return;
+  if (ys == 0 && ye == screenheight-1 && 
+      (n >= screenheight || -n >= screenheight))
+    {
+      PutStr(CL);
+      screeny = screenx = 0;
+      lp_missing = 0;
+      return;
+    }
+
+  if (lp_missing)
+    {
+      if (screenbot>ye || screenbot<ys)
+       missy = screenbot;
+      else
+       {
+         missy = screenbot - n;
+          if (missy>ye || missy<ys)
+           lp_missing = 0;
+       }
+    }
+
+  up = 1;
+  if (n < 0)
+    {
+      up = 0;
+      n = -n;
+    }
+  if (n >= ye-ys+1)
+    n = ye-ys+1;
+
+  oldtop = screentop;
+  oldbot = screenbot;
+  if (screenbot != ye)
+    ChangeScrollRegion(ys, ye);
+  alok = (AL || CAL || (ye == screenbot &&  up));
+  dlok = (DL || CDL || (ye == screenbot && !up));
+  if (screentop != ys && !(alok && dlok))
+    ChangeScrollRegion(ys, ye);
+
+  if (lp_missing && 
+      (oldbot != screenbot ||
+       (oldbot == screenbot && up && screentop == ys && screenbot == ye)))
+    {
+      /* Can't use FixLP */
+      GotoPos(screenwidth-1, oldbot);
+      SaveSetAttr(curr->attr[missy][screenwidth-1], curr->font[missy][screenwidth-1]);
+      PUTCHAR(curr->image[missy][screenwidth-1]);
+      RestoreAttr();
+      lp_missing = 0;
+      if (oldbot == screenbot)         /* have scrolled */
+       {
+         if (--n == 0)
+           {
+             ChangeScrollRegion(oldtop, oldbot);
+             return;
+           }
+       }
+    }
+
+  aldlfaster = (n > 1 && ye == screenbot && ((up && CDL) || (!up && CAL)));
+
+  if ((up || SR) && screentop == ys && screenbot == ye && !aldlfaster)
+    {
+      if (up)
+       {
+         GotoPos(0, ye);
+         while (n-- > 0)
+           PutStr(NL); /* was SF, I think NL is faster */
+       }
+      else
+       {
+         GotoPos(0, ys);
+         while (n-- > 0)
+           PutStr(SR);
+       }
+    }
+  else if (alok && dlok)
+    {
+      if (up || ye != screenbot)
+       {
+          GotoPos(0, up ? ys : ye+1-n);
+          if (CDL && !(n == 1 && DL))
+           CPutStr(CDL, n);
+         else
+           for(i=n; i--; )
+             PutStr(DL);
+       }
+      if (!up || ye != screenbot)
+       {
+          GotoPos(0, up ? ye+1-n : ys);
+          if (CAL && !(n == 1 && AL))
+           CPutStr(CAL, n);
+         else
+           for(i=n; i--; )
+             PutStr(AL);
+       }
+    }
+  else
+    {
+      Redisplay(0);
+      return;
+    }
+  if (lp_missing && missy != screenbot)
+    FixLP(screenwidth-1, missy);
+  ChangeScrollRegion(oldtop, oldbot);
+  if (lp_missing && missy != screenbot)
+    FixLP(screenwidth-1, missy);
+}
+
+static void ScrollUpMap(n)
+int n;
+{
+  char tmp[256 * sizeof(char *)];
+  register int ii, i, cnt1, cnt2;
+  register char **ppi, **ppa, **ppf;
+
+  i = curr->top + n;
+  cnt1 = n * sizeof(char *);
+  cnt2 = (curr->bot - i + 1) * sizeof(char *);
+  ppi = curr->image + i;
+  ppa = curr->attr + i;
+  ppf = curr->font + i;
+  for(ii = curr->top; ii < i; ii++)
+     AddLineToHist(curr, &curr->image[ii], &curr->attr[ii], &curr->font[ii]);
+  for (i = n; i; --i)
+    {
+      bclear(*--ppi, cols);
+      bzero(*--ppa, cols);
+      bzero(*--ppf, cols);
+    }
+  Scroll((char *) ppi, cnt1, cnt2, tmp);
+  Scroll((char *) ppa, cnt1, cnt2, tmp);
+  Scroll((char *) ppf, cnt1, cnt2, tmp);
+}
+
+static void ScrollDownMap(n)
+int n;
+{
+  char tmp[256 * sizeof(char *)];
+  register int i, cnt1, cnt2;
+  register char **ppi, **ppa, **ppf;
+
+  i = curr->top;
+  cnt1 = (curr->bot - i - n + 1) * sizeof(char *);
+  cnt2 = n * sizeof(char *);
+  Scroll((char *) (ppi = curr->image + i), cnt1, cnt2, tmp);
+  Scroll((char *) (ppa = curr->attr + i), cnt1, cnt2, tmp);
+  Scroll((char *) (ppf = curr->font + i), cnt1, cnt2, tmp);
+  for (i = n; i; --i)
+    {
+      bclear(*ppi++, cols);
+      bzero(*ppa++, cols);
+      bzero(*ppf++, cols);
+    }
+}
+
+static void Scroll(cp, cnt1, cnt2, tmp)
+char *cp, *tmp;
+int cnt1, cnt2;
+{
+  if (!cnt1 || !cnt2)
+    return;
+  if (cnt1 <= cnt2)
+    {
+      bcopy(cp, tmp, cnt1);
+      bcopy(cp + cnt1, cp, cnt2);
+      bcopy(tmp, cp + cnt2, cnt1);
+    }
+  else
+    {
+      bcopy(cp + cnt1, tmp, cnt2);
+      bcopy(cp, cp + cnt2, cnt1);
+      bcopy(tmp, cp, cnt2);
+    }
+}
+
+static void ForwardTab()
+{
+  register int x = curr->x;
+
+  if (x == cols)
+    {
+      LineFeed(2);
+      x = 0;
+    }
+  if (curr->tabs[x] && x < cols - 1)
+    x++;
+  while (x < cols - 1 && !curr->tabs[x])
+    x++;
+  GotoPos(x, curr->y);
+  curr->x = x;
+}
+
+static void BackwardTab()
+{
+  register int x = curr->x;
+
+  if (curr->tabs[x] && x > 0)
+    x--;
+  while (x > 0 && !curr->tabs[x])
+    x--;
+  GotoPos(x, curr->y);
+  curr->x = x;
+}
+
+static void ClearScreen()
+{
+  register int i;
+  register char **ppi = curr->image, **ppa = curr->attr, **ppf = curr->font;
+
+  for (i = 0; i < rows; ++i)
+    {
+      AddLineToHist(curr, ppi, ppa, ppf);
+      bclear(*ppi++, cols);
+      bzero(*ppa++, cols);
+      bzero(*ppf++, cols);
+    }
+  if (display)
+    {
+      PutStr(CL);
+      screenx = screeny = 0;
+      lp_missing = 0;
+    }
+}
+
+static void ClearFromBOS()
+{
+  register int n, y = curr->y, x = curr->x;
+
+  for (n = 0; n < y; ++n)
+    ClearInLine(1, n, 0, cols - 1);
+  ClearInLine(1, y, 0, x);
+  GotoPos(x, y);
+  RestoreAttr();
+}
+
+static void ClearToEOS()
+{
+  register int n, y = curr->y, x = curr->x;
+
+  if (!y && !x)
+    {
+      ClearScreen();
+      return;
+    }
+  if (display && CD)
+    {
+      PutStr(CD);
+      lp_missing = 0;
+    }
+  ClearInLine(!CD, y, x, cols - 1);
+  for (n = y + 1; n < rows; n++)
+    ClearInLine(!CD, n, 0, cols - 1);
+  GotoPos(x, y);
+  RestoreAttr();
+}
+
+static void ClearLine()
+{
+  register int y = curr->y, x = curr->x;
+
+  ClearInLine(1, y, 0, cols - 1);
+  GotoPos(x, y);
+  RestoreAttr();
+}
+
+static void ClearToEOL()
+{
+  register int y = curr->y, x = curr->x;
+
+  ClearInLine(1, y, x, cols - 1);
+  GotoPos(x, y);
+  RestoreAttr();
+}
+
+static void ClearFromBOL()
+{
+  register int y = curr->y, x = curr->x;
+
+  ClearInLine(1, y, 0, x);
+  GotoPos(x, y);
+  RestoreAttr();
+}
+
+static void ClearInLine(displ, y, x1, x2)
+int displ, y, x1, x2;
+{
+  register int n;
+
+  if (x1 == cols)
+    x1--;
+  if (x2 == cols)
+    x2--;
+  if ((n = x2 - x1 + 1) != 0)
+    {
+      if (displ && display)
+       {
+         if (x2 == cols - 1 && CE)
+           {
+             GotoPos(x1, y);
+             PutStr(CE);
+             if (y == screenbot)
+               lp_missing = 0;
+           }
+         else
+           DisplayLine(curr->image[y], curr->attr[y], curr->font[y],
+                       blank, null, null, y, x1, x2);
+       }
+      if (curr)
+       {
+          bclear(curr->image[y] + x1, n);
+          bzero(curr->attr[y] + x1, n);
+          bzero(curr->font[y] + x1, n);
+       }
+    }
+}
+
+static void CursorRight(n)
+register int n;
+{
+  register int x = curr->x;
+
+  if (x == cols)
+    {
+      LineFeed(2);
+      x = 0;
+    }
+  if ((curr->x += n) >= cols)
+    curr->x = cols - 1;
+  GotoPos(curr->x, curr->y);
+}
+
+static void CursorUp(n)
+register int n;
+{
+  if (curr->y < curr->top)             /* if above scrolling rgn, */
+    {
+      if ((curr->y -= n) < 0)          /* ignore its limits      */
+         curr->y = 0;
+    }
+  else
+    if ((curr->y -= n) < curr->top)
+      curr->y = curr->top;
+  GotoPos(curr->x, curr->y);
+}
+
+static void CursorDown(n)
+register int n;
+{
+  if (curr->y > curr->bot)             /* if below scrolling rgn, */
+    {
+      if ((curr->y += n) > rows - 1)   /* ignore its limits      */
+        curr->y = rows - 1;
+    }
+  else
+    if ((curr->y += n) > curr->bot)
+      curr->y = curr->bot;
+  GotoPos(curr->x, curr->y);
+}
+
+static void CursorLeft(n)
+register int n;
+{
+  if ((curr->x -= n) < 0)
+    curr->x = 0;
+  GotoPos(curr->x, curr->y);
+}
+
+static void ASetMode(on)
+int on;
+{
+  register int i;
+
+  for (i = 0; i < curr->NumArgs; ++i)
+    {
+      switch (curr->args[i])
+       {
+       case 4:
+         curr->insert = on;
+         InsertMode(on);
+         break;
+       }
+    }
+}
+
+static void SelectRendition()
+{
+  register int i = 0, a = curr->LocalAttr;
+
+  do
+    {
+      switch (curr->args[i])
+       {
+       case 0:
+         a = 0;
+         break;
+       case 1:
+         a |= A_BD;
+         break;
+       case 2:
+         a |= A_DI;
+         break;
+       case 3:
+         a |= A_SO;
+         break;
+       case 4:
+         a |= A_US;
+         break;
+       case 5:
+         a |= A_BL;
+         break;
+       case 7:
+         a |= A_RV;
+         break;
+       case 22:
+         a &= ~(A_BD | A_SO | A_DI);
+         break;
+       case 23:
+         a &= ~A_SO;
+         break;
+       case 24:
+         a &= ~A_US;
+         break;
+       case 25:
+         a &= ~A_BL;
+         break;
+       case 27:
+         a &= ~A_RV;
+         break;
+       }
+    } while (++i < curr->NumArgs);
+  NewRendition(curr->LocalAttr = a);
+}
+
+void
+NewRendition(new)
+register int new;
+{
+  register int i, old = GlobalAttr;
+
+  if (!display || old == new)
+    return;
+  GlobalAttr = new;
+  for (i = 1; i <= A_MAX; i <<= 1)
+    {
+      if ((old & i) && !(new & i))
+       {
+         PutStr(UE);
+         PutStr(SE);
+         PutStr(ME);
+         if (new & A_DI)
+           PutStr(attrtab[ATTR_DI]);
+         if (new & A_US)
+           PutStr(attrtab[ATTR_US]);
+         if (new & A_BD)
+           PutStr(attrtab[ATTR_BD]);
+         if (new & A_RV)
+           PutStr(attrtab[ATTR_RV]);
+         if (new & A_SO)
+           PutStr(attrtab[ATTR_SO]);
+         if (new & A_BL)
+           PutStr(attrtab[ATTR_BL]);
+         return;
+       }
+    }
+  if ((new & A_DI) && !(old & A_DI))
+    PutStr(attrtab[ATTR_DI]);
+  if ((new & A_US) && !(old & A_US))
+    PutStr(attrtab[ATTR_US]);
+  if ((new & A_BD) && !(old & A_BD))
+    PutStr(attrtab[ATTR_BD]);
+  if ((new & A_RV) && !(old & A_RV))
+    PutStr(attrtab[ATTR_RV]);
+  if ((new & A_SO) && !(old & A_SO))
+    PutStr(attrtab[ATTR_SO]);
+  if ((new & A_BL) && !(old & A_BL))
+    PutStr(attrtab[ATTR_BL]);
+}
+
+void
+SaveSetAttr(newattr, newcharset)
+int newattr, newcharset;
+{
+  NewRendition(newattr);
+  NewCharset(newcharset);
+}
+
+void
+RestoreAttr()
+{
+  NewRendition(curr->LocalAttr);
+  NewCharset(curr->charsets[curr->LocalCharset]);
+}
+
+static void FillWithEs()
+{
+  register int i;
+  register char *p, *ep;
+
+  curr->y = curr->x = 0;
+  for (i = 0; i < rows; ++i)
+    {
+      bzero(curr->attr[i], cols);
+      bzero(curr->font[i], cols);
+      p = curr->image[i];
+      ep = p + cols;
+      while (p < ep)
+       *p++ = 'E';
+    }
+  if (display)
+    Redisplay(0);
+}
+
+/*
+ * if cur_only, we only redisplay current line, as a full refresh is
+ * too expensive.
+ */
+void Redisplay(cur_only)
+int cur_only;
+{
+  register int i, stop;
+
+  PutStr(CL);
+  screenx = screeny = 0;
+  lp_missing = 0;
+  stop = rows; i = 0;
+  if (cur_only)
+    {
+      i = stop = curr->y;
+      stop++;
+    }
+  for (; i < stop; ++i)
+    {
+      if (in_ovl)
+       (*ovl_RedisplayLine)(i, 0, cols - 1, 1);
+      else
+        DisplayLine(blank, null, null, curr->image[i], curr->attr[i],
+                   curr->font[i], i, 0, cols - 1);
+    }
+  if (!in_ovl)
+    {
+      GotoPos(curr->x, curr->y);
+      NewRendition(curr->LocalAttr);
+      NewCharset(curr->charsets[curr->LocalCharset]);
+    }
+}
+
+void
+DisplayLine(os, oa, of, s, as, fs, y, from, to)
+int from, to, y;
+register char *os, *oa, *of, *s, *as, *fs;
+{
+  register int x;
+  int last2flag = 0, delete_lp = 0;
+
+  if (!LP && y == screenbot && to == cols - 1)
+    if (lp_missing
+       || s[to] != os[to] || as[to] != oa[to] || of[to] != fs[to])
+      {
+       if ((IC || IM) && (from < to || !in_ovl))
+         {
+           if ((to -= 2) < from - 1)
+             from--;
+           last2flag = 1;
+           lp_missing = 0;
+         }
+       else
+         {
+           to--;
+           delete_lp = (CE || DC || CDC);
+           lp_missing = (s[to] != ' ' || as[to] || fs[to]);
+         }
+      }
+    else
+      to--;
+  for (x = from; x <= to; ++x)
+    {
+      if (s[x] == os[x] && as[x] == oa[x] && of[x] == fs[x])
+       continue;
+      GotoPos(x, y);
+      NewRendition(as[x]);
+      NewCharset(fs[x]);
+      PUTCHAR(s[x]);
+    }
+  if (last2flag)
+    {
+      GotoPos(x, y);
+      NewRendition(as[x + 1]);
+      NewCharset(fs[x + 1]);
+      PUTCHAR(s[x + 1]);
+      GotoPos(x, y);
+      NewRendition(as[x]);
+      NewCharset(fs[x]);
+      INSERTCHAR(s[x]);
+    }
+  else if (delete_lp)
+    {
+      if (DC)
+       PutStr(DC);
+      else if (CDC)
+       CPutStr(CDC, 1);
+      else if (CE)
+       PutStr(CE);
+    }
+}
+
+void
+RefreshLine(y, from, to)
+int y, from, to;
+{
+  char *oi = null;
+
+  if (CE && to == screenwidth-1)
+    {
+      GotoPos(from, y);
+      PutStr(CE);
+      oi = blank;
+    }
+  if (in_ovl)
+    (*ovl_RedisplayLine)(y, from, to, (oi == blank));
+  else
+    DisplayLine(oi, null, null, curr->image[y], curr->attr[y],
+                curr->font[y], y, from, to);
+}
+
+static void RedisplayLine(os, oa, of, y, from, to)
+int from, to, y;
+char *os, *oa, *of;
+{
+  DisplayLine(os, oa, of, curr->image[y], curr->attr[y],
+             curr->font[y], y, from, to);
+  NewRendition(curr->LocalAttr);
+  NewCharset(curr->charsets[curr->LocalCharset]);
+}
+
+void
+FixLP(x2, y2)
+register int x2, y2;
+{
+  register struct win *p = curr;
+
+  GotoPos(x2, y2);
+  SaveSetAttr(p->attr[y2][x2], p->font[y2][x2]);
+  PUTCHAR(p->image[y2][x2]);
+  RestoreAttr();
+  lp_missing = 0;
+}
+
+void
+CheckLP(n_ch)
+char n_ch;
+{
+  register int y = screenbot, x = cols - 1;
+  register char n_at, n_fo, o_ch, o_at, o_fo;
+
+  o_ch = curr->image[y][x];
+  o_at = curr->attr[y][x];
+  o_fo = curr->font[y][x];
+
+  n_at = curr->LocalAttr;
+  n_fo = curr->charsets[curr->LocalCharset];
+
+  lp_missing = 0;
+  if (n_ch == o_ch && n_at == o_at && n_fo == o_fo)
+    {
+      return;
+    }
+  if (n_ch != ' ' || n_at || n_fo)
+    lp_missing = 1;
+  if (o_ch != ' ' || o_at || o_fo)
+    {
+      if (DC)
+       PutStr(DC);
+      else if (CDC)
+       CPutStr(CDC, 1);
+      else if (CE)
+       PutStr(CE);
+      else
+       lp_missing = 1;
+    }
+}
+
+static void FindAKA()
+{
+  register char *cp, *line, ch;
+  register struct win *wp = curr;
+  register int len = strlen(wp->cmd);
+  int y;
+
+  y = (wp->autoaka > 0 && wp->autoaka <= wp->height) ? wp->autoaka - 1 : wp->y;
+  cols = wp->width;
+ try_line:
+  cp = line = wp->image[y];
+  if (wp->autoaka > 0 && (ch = *wp->cmd) != '\0')
+    {
+      for (;;)
+       {
+         if ((cp = index(cp, ch)) != NULL
+             && !strncmp(cp, wp->cmd, len))
+           break;
+         if (!cp || ++cp - line >= cols - len)
+           {
+             if (++y == wp->autoaka && y < rows)
+               goto try_line;
+             return;
+           }
+       }
+      cp += len;
+    }
+  for (len = cols - (cp - line); len && *cp == ' '; len--, cp++)
+    ;
+  if (len)
+    {
+      if (wp->autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^'))
+       wp->autoaka = -1;
+      else
+       wp->autoaka = 0;
+      line = wp->cmd + wp->akapos;
+      while (len && *cp != ' ')
+       {
+         if ((*line++ = *cp++) == '/')
+           line = wp->cmd + wp->akapos;
+         len--;
+       }
+      *line = '\0';
+    }
+  else
+    wp->autoaka = 0;
+}
+
+
+/* We dont use HS status line with Input.
+ * If we would use it, then we should check e_tgetflag("es") if
+ * we are allowed to use esc sequences there.
+ * For now, we hope that Goto(,,STATLINE,0) brings us in the bottom
+ * line. jw.
+ */
+
+static char inpbuf[101];
+static int inplen;
+static int inpmaxlen;
+static char *inpstring;
+static int inpstringlen;
+static void (*inpfinfunc)();
+
+void
+Input(istr, len, finfunc)
+char *istr;
+int len;
+void (*finfunc)();
+{
+  int maxlen;
+
+  inpstring = istr;
+  inpstringlen = strlen(istr);
+  if (len > 100)
+    len = 100;
+  maxlen = screenwidth - inpstringlen;
+  if (!LP && STATLINE == screenbot)
+    maxlen--;
+  if (len > maxlen)
+    len = maxlen;
+  if (len < 2)
+    {
+      Msg(0, "Width too small");
+      return;
+    }
+  inpmaxlen = len;
+  inpfinfunc = finfunc;
+  InitOverlayPage(process_inp_input, inpRedisplayLine, (int (*)())0, 1);
+  inplen = 0;
+  GotoPos(0, STATLINE);
+  if (CE)
+    PutStr(CE);
+  else
+    {
+      DisplayLine(curr->image[screeny], curr->attr[screeny],
+                 curr->font[screeny],
+                 blank, null, null, screeny, 0, cols - 1);
+    }
+  inpRedisplayLine(STATLINE, 0, inpstringlen - 1, 0);
+  GotoPos(inpstringlen, STATLINE);
+}
+
+static void
+process_inp_input(ppbuf, plen)
+char **ppbuf;
+int *plen;
+{
+  int len, x;
+  char *pbuf;
+  char ch;
+
+  if (ppbuf == 0)
+    {
+      AbortInp();
+      return;
+    }
+  x = inpstringlen+inplen;
+  len = *plen;
+  pbuf = *ppbuf;
+  while (len)
+    {
+      ch = *pbuf++;
+      len--;
+      if (ch >= ' ' && ch <= '~' && inplen < inpmaxlen)
+       {
+         inpbuf[inplen++] = ch;
+         GotoPos(x, STATLINE);
+         SaveSetAttr(A_SO, ASCII);
+         PUTCHAR(ch);
+         x++;
+       }
+      else if ((ch == '\b' || ch == 0177) && inplen > 0)
+       {
+         inplen--;
+         x--;
+         GotoPos(x, STATLINE);
+         SaveSetAttr(0, ASCII);
+         PUTCHAR(' ');
+         GotoPos(x, STATLINE);
+       }
+      else if (ch == '\004' || ch == '\003' || ch == '\000' || ch == '\n' || ch == '\r')
+       {
+          if (ch != '\n' && ch != '\r')
+           inplen = 0;
+         inpbuf[inplen] = 0;
+          AbortInp(); /* redisplays... */
+          (*inpfinfunc)(inpbuf, inplen);
+         break;
+       }
+    }
+  *ppbuf = pbuf;
+  *plen = len;
+}
+
+static void
+AbortInp()
+{
+  in_ovl = 0;  /* So we can use RefreshLine() */
+  RefreshLine(STATLINE, 0, screenwidth-1);
+  ExitOverlayPage();
+}
+
+static void
+inpRedisplayLine(y, xs, xe, isblank)
+int y, xs, xe, isblank;
+{
+  int q, r, s, l, v;
+
+  if (y != STATLINE)
+    return;
+  inpbuf[inplen] = 0;
+  GotoPos(xs,y);
+  q = xs;
+  v = xe - xs + 1;
+  s = 0;
+  r = inpstringlen;
+  if (v > 0 && q < r)
+    {
+      SaveSetAttr(A_SO, ASCII);
+      l = v;
+      if (l > r-q)
+       l = r-q;
+      printf("%-*.*s", l, l, inpstring + q - s);
+      q += l;
+      v -= l;
+    }
+  s = r;
+  r += inplen;
+  if (v > 0 && q < r)
+    {
+      SaveSetAttr(A_SO, ASCII);
+      l = v;
+      if (l > r-q)
+       l = r-q;
+      printf("%-*.*s", l, l, inpbuf + q - s);
+      q += l;
+      v -= l;
+    }
+  s = r;
+  r = screenwidth;
+  if (!isblank && v > 0 && q < r)
+    {
+      SaveSetAttr(0, ASCII);
+      l = v;
+      if (l > r-q)
+       l = r-q;
+      printf("%-*.*s", l, l, "");
+      q += l;
+    }
+  SetLastPos(q, y);
+}
+
+static void
+AKAfin(buf, len)
+char *buf;
+int len;
+{
+  if (len)
+    {
+      strcpy(curr->cmd + curr->akapos, buf);
+    }
+}
+
+void
+InputAKA()
+{
+  void Input(), AKAfin();
+
+  Input("Set window's a.k.a. to: ", 20, AKAfin);
+}
+
+static void
+Colonfin(buf, len)
+char *buf;
+int len;
+{
+  if (len)
+    RcLine(buf);
+}
+
+void
+InputColon()
+{
+  void Input(), Colonfin();
+
+  Input(":", 100, Colonfin);
+}
+
+void
+MakeBlankLine(p, n)
+register char *p;
+register int n;
+{
+  while (n--)
+    *p++ = ' ';
+}
+
+void
+MakeStatus(msg)
+char *msg;
+{
+  register char *s, *t;
+  register int max, ti;
+
+  SetCurr(fore);
+  display = 1;
+  if (!(max = HS))
+    {
+      max = !LP ? cols - 1 : cols;
+    }
+  if (status)
+    {
+      if (!BellDisplayed)
+       {
+         ti = time((time_t *) 0) - TimeDisplayed;
+         if (ti < MsgMinWait)
+           sleep(MsgMinWait - ti);
+       }
+      RemoveStatus();
+    }
+  for (s = t = msg; *s && t - msg < max; ++s)
+    if (*s == BELL)
+      PutStr(BL);
+    else if (*s >= ' ' && *s <= '~')
+      *t++ = *s;
+  *t = '\0';
+  if (t > msg)
+    {
+      strncpy(LastMsg, msg, maxwidth);
+      status = 1;
+      status_lastx = screenx;
+      status_lasty = screeny;
+      StatLen = t - msg;
+      if (!HS)
+       {
+         GotoPos(0, STATLINE);
+          SaveSetAttr(A_SO, ASCII);
+         InsertMode(0);
+         printf("%s", msg);
+          screenx = -1;
+       }
+      else
+       {
+         debug("HS:");
+          SaveSetAttr(0, ASCII);
+         InsertMode(0);
+         CPutStr(TS, 0);
+         printf("%s", msg);
+         PutStr(FS);
+       }
+      (void) fflush(stdout);
+      (void) time(&TimeDisplayed);
+    }
+}
+
+void
+RemoveStatus()
+{
+  if (!status)
+    return;
+  status = 0;
+  BellDisplayed = 0;
+  SetCurr(fore);
+  display = 1;
+  if (!HS)
+    {
+      GotoPos(0, STATLINE);
+      if (in_ovl)
+       (*ovl_RedisplayLine)(STATLINE, 0, StatLen - 1, 0);
+      else
+       RedisplayLine(null, null, null, STATLINE, 0, StatLen - 1);
+      GotoPos(status_lastx, status_lasty);
+    }
+  else
+    {
+      SaveSetAttr(0, ASCII);
+      PutStr(DS);
+    }
+}
+
+void
+ClearDisplay()
+{
+  PutStr(CL);
+  screeny = screenx = 0;
+  fflush(stdout);
+}
+
+static void SetCurr(wp)
+struct win *wp;
+{
+  curr = wp;
+  cols = curr->width;
+  rows = curr->height;
+  display = curr->active;
+}
+
+void
+InitOverlayPage(pro, red, rewrite, blockfore)
+void (*pro)();
+void (*red)();
+int (*rewrite)();
+int blockfore;
+{
+  RemoveStatus();
+  SetOvlCurr();
+  ChangeScrollRegion(0, screenheight - 1);
+  SetFlow(1);
+  ovl_process = pro;
+  ovl_RedisplayLine = red;
+  ovl_Rewrite = rewrite;
+  ovl_blockfore = blockfore;
+  curr->active = 0;
+  in_ovl = 1;
+}
+
+void
+ExitOverlayPage()
+{
+  ChangeScrollRegion(curr->top, curr->bot);
+  GotoPos(curr->x, curr->y);
+  RestoreAttr();
+  SetFlow(curr->flow & FLOW_NOW);
+  curr->active = 1;
+  in_ovl = 0;
+}
+
+void
+SetOvlCurr()
+{
+  SetCurr(fore);
+  SaveSetAttr(0, ASCII);
+  InsertMode(0);
+  display = 1;
+}
+
+void
+SetLastPos(x,y)
+int x,y;
+{
+  screenx = x;
+  screeny = y;
+}
+
+void
+WSresize(width, height)
+int width, height;
+{
+  debug2("(display=%d:WSresize says:'%s'\n", display, tgoto(WS, width, height));
+  PutStr(tgoto(WS, width, height));
+}
+
+void
+ChangeScrollRegion(top, bot)
+int top, bot;
+{
+  if (display == 0)
+    return;
+  if (CS == 0)
+    {
+      screentop = 0;
+      screenbot = screenheight - 1;
+      return;
+    }
+  if (top == screentop && bot == screenbot)
+    return;
+  debug2("ChangeScrollRegion: (%d - %d)\n", top, bot);
+  PutStr(tgoto(CS, bot, top));
+  screentop = top;
+  screenbot = bot;
+  screeny = screenx = -1;              /* Just in case... */
+}
+
+
+void AddLineToHist(wp, pi, pa, pf)
+struct win *wp;
+char **pi, **pa, **pf;
+{
+  register char *q;
+
+  if (wp->histheight == 0)
+    return;
+  q = *pi; *pi = wp->ihist[wp->histidx]; wp->ihist[wp->histidx] = q;
+  q = *pa; *pa = wp->ahist[wp->histidx]; wp->ahist[wp->histidx] = q;
+  q = *pf; *pf = wp->fhist[wp->histidx]; wp->fhist[wp->histidx] = q;
+  if (++wp->histidx >= wp->histheight)
+    wp->histidx = 0;
+}
+
+
+/*
+ *
+ *  Termcap routines that use our extra_incap
+ *
+ */
+
+/* findcap:
+ *   cap = capability we are looking for
+ *   tepp = pointer to bufferpointer
+ *   n = size of buffer (0 = infinity)
+ */
+
+char *
+findcap(cap, tepp, n)
+char *cap;
+char **tepp;
+int n;
+{
+  char *tep;
+  char c, *p, *cp;
+  int mode;    /* mode: 0=LIT  1=^  2=\x  3,4,5=\nnn */
+  int num = 0, capl;
+
+  if (!extra_incap)
+    return (0);
+  tep = *tepp;
+  capl = strlen(cap);
+  cp = 0;
+  mode = 0;
+  for (p = extra_incap; *p; )
+    {
+      if (strncmp(p, cap, capl) == 0)
+       {
+         p+=capl;
+         c = *p;
+         if (c && c != ':' && c != '@')
+           p++;
+         if (c == 0 || c == '@' || c == '=' || c == ':' || c == '#')
+           cp = tep;
+       }
+      while (c = *p)
+       {
+         p++;
+         if (mode == 0)
+           {
+             if (c == ':')
+               break;
+             if (c == '^')
+               mode = 1;
+             if (c == '\\')
+               mode = 2;
+           }
+         else if (mode == 1)
+           {
+             c = c & 0x1f;
+             mode = 0;
+           }
+         else if (mode == 2)
+           {
+             switch(c)
+               {
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                 mode = 3;
+                 num = 0;
+                 break;
+               case 'E':
+                 c = 27;
+                 break;
+               case 'n':
+                 c = '\n';
+                 break;
+               case 'r':
+                 c = '\r';
+                 break;
+               case 't':
+                 c = '\t';
+                 break;
+               case 'b':
+                 c = '\b';
+                 break;
+               case 'f':
+                 c = '\f';
+                 break;
+               }
+             if (mode == 2)
+               mode = 0;
+           }
+         if (mode > 2)
+           {
+             num = num * 8 + (c - '0');
+             if (mode++ == 5 || (*p < '0' || *p > '9'))
+               {
+                 c = num;
+                 mode = 0;
+               }
+           }
+         if (mode)
+           continue;
+
+         if (cp && n != 1)
+           {
+             *cp++ = c;
+             n--;
+           }
+       }
+      if (cp)
+       {
+         *cp++ = 0;
+         *tepp = cp;
+         debug2("'%s' found in extra_incap -> %s\n", cap, tep);
+         return(tep);
+       }
+    }
+  return(0);
+}
+
+static char *
+e_tgetstr(cap, tepp)
+char *cap;
+char **tepp;
+{
+  char *tep;
+  if (tep = findcap(cap, tepp, 0))
+    return((*tep == '@') ? 0 : tep);
+  return (tgetstr(cap, tepp));
+}
+
+static int
+e_tgetflag(cap)
+char *cap;
+{
+  char buf[2], *bufp;
+  char *tep;
+  bufp = buf;
+  if (tep = findcap(cap, &bufp, 2))
+    return((*tep == '@') ? 0 : 1);
+  return (tgetflag(cap));
+}
+
+static int
+e_tgetnum(cap)
+char *cap;
+{
+  char buf[20], *bufp;
+  char *tep, c;
+  int res, base = 10;
+
+  bufp = buf;
+  if (tep = findcap(cap, &bufp, 20))
+    {
+      c = *tep;
+      if (c == '@')
+       return(-1);
+      if (c == '0')
+       base = 8;
+      res = 0;
+      while ((c = *tep++) >= '0' && c <= '9')
+       res = res * base + (c - '0');
+      return(res);
+    }
+  return (tgetnum(cap));
+}
diff --git a/usr/othersrc/public/screen-3.2/screen3.2/ansi.h b/usr/othersrc/public/screen-3.2/screen3.2/ansi.h
new file mode 100644 (file)
index 0000000..4309275
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (c) 1991
+ *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Noteworthy contributors to screen's design and implementation:
+ *     Wayne Davison (davison@borland.com)
+ *     Patrick Wolfe (pat@kai.com, kailand!pat)
+ *     Bart Schaefer (schaefer@cse.ogi.edu)
+ *     Nathan Glasser (nathan@brokaw.lcs.mit.edu)
+ *     Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
+ *     Howard Chu (hyc@hanauma.jpl.nasa.gov)
+ *     Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
+ *     Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
+ *     Marc Boucher (marc@CAM.ORG)
+ *
+ ****************************************************************
+ * $Id: ansi.h,v 1.2 92/02/03 02:27:39 jnweiger Exp $ FAU
+ */
+
+#define NATTR          6
+
+#define ATTR_DI                0       /* Dim mode */
+#define ATTR_US                1       /* Underscore mode */
+#define ATTR_BD                2       /* Bold mode */
+#define ATTR_RV                3       /* Reverse mode */
+#define ATTR_SO                4       /* Standout mode */
+#define ATTR_BL                5       /* Blinking */
+
+#define A_DI   (1<<ATTR_DI)
+#define A_US   (1<<ATTR_US)
+#define A_BD   (1<<ATTR_BD)
+#define A_RV   (1<<ATTR_RV)
+#define A_SO   (1<<ATTR_SO)
+#define A_BL   (1<<ATTR_BL)
+#define A_MAX  (1<<(NATTR-1))
+
+/* Types of movement used by GotoPos() */
+enum move_t {
+       M_NONE,
+       M_UP,
+       M_CUP,
+       M_DO,
+       M_CDO,
+       M_LE,
+       M_CLE,
+       M_RI,
+       M_CRI,
+       M_RW,
+       M_CR    /* CR and rewrite */
+};
+
+#define EXPENSIVE       1000
+
+#define G0                      0
+#define G1                      1
+#define G2                      2
+#define G3                      3
+
+#define ASCII           0
+
+#ifdef TOPSTAT
+#define STATLINE        (0)
+#else
+#define STATLINE        (screenheight-1)
+#endif
+
diff --git a/usr/othersrc/public/screen-3.2/screen3.2/fileio.c b/usr/othersrc/public/screen-3.2/screen3.2/fileio.c
new file mode 100644 (file)
index 0000000..96d24a6
--- /dev/null
@@ -0,0 +1,2576 @@
+/* Copyright (c) 1991
+ *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Noteworthy contributors to screen's design and implementation:
+ *     Wayne Davison (davison@borland.com)
+ *     Patrick Wolfe (pat@kai.com, kailand!pat)
+ *     Bart Schaefer (schaefer@cse.ogi.edu)
+ *     Nathan Glasser (nathan@brokaw.lcs.mit.edu)
+ *     Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
+ *     Howard Chu (hyc@hanauma.jpl.nasa.gov)
+ *     Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
+ *     Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
+ *     Marc Boucher (marc@CAM.ORG)
+ *
+ ****************************************************************
+ */
+
+#ifndef lint
+  static char rcs_id[] = "$Id: fileio.c,v 1.2 92/02/03 02:27:42 jnweiger Exp $ FAU";
+#endif
+
+#if defined(pyr) || defined(MIPS) || defined(GOULD_NP1) || defined(B43)
+extern int errno;
+#endif
+#include <sys/types.h>
+#ifndef sgi
+# include <sys/file.h>
+#endif /* sgi */
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef BSDI
+# include <sys/signal.h>
+#endif /* BSDI */
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+#ifdef _SEQUENT_
+# define UTHOST                /* _SEQUENT_ has got ut_find_host() */
+#endif
+
+#ifndef GETUTENT
+# ifdef GETTTYENT
+#  include <ttyent.h>
+# else
+struct ttyent
+{
+  char *ty_name;
+};
+static char *tt, *ttnext;
+static char ttys[] = "/etc/ttys";
+# endif
+#endif
+
+#ifdef LOADAV
+# ifndef NeXT
+#  include <nlist.h>
+
+static char KmemName[] = "/dev/kmem";
+#  if defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi)
+static char UnixName[] = "/unix";
+#  else
+#   ifdef sequent
+static char UnixName[] = "/dynix";
+#   else
+#    ifdef hpux
+static char UnixName[] = "/hp-ux";
+#    else
+#     ifdef xelos
+static char UnixName[] = "/xelos";
+#     else
+static char UnixName[] = "/vmunix";
+#     endif /* xelos */
+#    endif /* hpux */
+#   endif /* sequent */
+#  endif /* _SEQUENT_ ... */
+
+#  ifdef alliant
+static char AvenrunSym[] = "_Loadavg";
+#  else
+#   if defined(hpux) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi)
+static char AvenrunSym[] = "avenrun";
+#   else
+static char AvenrunSym[] = "_avenrun";
+#   endif
+#  endif /* alliant */
+static struct nlist nl[2];
+int avenrun;
+static kmemf;
+#  ifdef LOADAV_3LONGS
+long loadav[3];
+#  else
+#   ifdef LOADAV_4LONGS
+long loadav[4];
+#   else
+double loadav[3];
+#   endif
+#  endif
+# else /* NeXT */
+#  include <mach.h>
+kern_return_t error;
+host_t host;
+unsigned int info_count;
+struct processor_set_basic_info info;
+processor_set_t default_set;
+float loadav;
+int avenrun;
+# endif /* NeXT */
+#endif /* LOADAV */
+
+#if defined(UTMPOK) && defined(GETUTENT) && !defined(SVR4)
+# if defined(hpux) /* cruel hpux release 8.0 */
+#  define pututline _pututline
+# endif /* hpux */
+extern struct utmp *getutline(), *pututline();
+# if defined(_SEQUENT_)
+extern struct utmp *ut_add_user(), *ut_delete_user();
+extern char *ut_find_host();
+# endif
+#endif
+#ifdef NETHACK
+extern nethackflag;
+#endif
+int hardcopy_append = 0;
+int all_norefresh = 0;
+
+extern char *RcFileName, *home, *extra_incap, *extra_outcap;
+extern char *BellString, *ActivityString, *ShellProg, *ShellArgs[];
+extern char *BufferFile, *PowDetachString, *VisualBellString;
+extern int VBellWait, MsgWait, MsgMinWait;
+extern struct key ktab[];
+extern char Esc, MetaEsc;
+extern char *shellaka, SockPath[], *SockNamePtr, *LoginName;
+extern int loginflag, allflag, TtyMode, auto_detach;
+extern int iflag, rflag, dflag;
+extern int default_flow, wrap;
+extern HS, termcapHS, use_hardstatus, visual_bell, default_monitor;
+extern int default_histheight;
+extern int default_startup;
+extern int slowpaste;
+extern DeadlyMsg, HasWindow;
+extern ForeNum, screenwidth, screenheight;
+extern char display_tty[];
+extern struct win *fore;
+extern char screenterm[];
+extern int join_with_cr;
+extern struct mode OldMode, NewMode;
+extern int HasWindow;
+extern char mark_key_tab[];
+extern int real_uid, eff_uid;
+extern int real_gid, eff_gid;
+
+#ifdef PASSWORD
+int CheckPassword;
+char Password[20];
+#endif
+
+#ifdef COPY_PASTE
+extern char *copybuffer;
+extern copylen;
+#endif
+
+static char *CatExtra __P((char *, char *));
+static char **SaveArgs __P((int, char **));
+static int Parse __P((char *, char *[]));
+static char *ParseChar __P((char *, char *));
+static void ParseNum __P((int, char *[], int*));
+static void ParseOnOff __P((int, char *[], int*));
+static void ParseSaveStr __P((int, char *[], char **, char *));
+static int IsNum __P((char *, int));
+static int IsNumColon __P((char *, int, char *, int));
+static slot_t TtyNameSlot __P((char *));
+
+#if !defined(GETTTYENT) && !defined(GETUTENT)
+static void setttyent __P((void));
+static struct ttyent *getttyent __P((void));
+#endif
+
+/*
+ * XXX: system
+ */
+extern time_t time __P((time_t *));
+#if !defined(BSDI) && !defined(SVR4)
+extern char *getpass __P((char *));
+#endif /* !BSDI && !SVR4 */
+#if defined(LOADAV) && !defined(NeXT) && !defined(NLIST_DECLARED)
+extern int nlist __P((char *, struct nlist *));
+#endif
+
+char *KeyNames[] = 
+{
+  "screen",
+  "select0", "select1", "select2", "select3", "select4",
+  "select5", "select6", "select7", "select8", "select9",
+  "aka", "clear", "colon", "copy", "detach", "flow",
+  "hardcopy", "help", "histnext", "history", "info", "kill", "lastmsg",
+  "license",
+  "lockscreen", "log", "login", "monitor", "next", "other", "paste",
+  "pow_detach", "prev", "quit", "readbuf", "redisplay", "removebuf",
+  "reset", "set", "shell", "suspend", "termcap", "time", "vbell",
+  "version", "width", "windows", "wrap", "writebuf", "xoff", "xon",
+  0,
+};
+
+
+/* Must be in alpha order !!! */
+
+char *RCNames[] =
+{
+  "activity", "all", "autodetach", "bell", "bind", "bufferfile", "chdir",
+  "crlf", "echo", "escape", "flow", "hardcopy_append", "hardstatus", "login", 
+  "markkeys", "mode", "monitor", "msgminwait", "msgwait", "nethack", "password",
+  "pow_detach_msg", "redraw", "refresh", "screen", "scrollback", "shell", 
+  "shellaka", "sleep", "slowpaste", "startup_message", "term", "termcap",
+  "terminfo", "vbell", "vbell_msg", "vbellwait", "visualbell",
+  "visualbell_msg", "wrap",
+};
+
+enum RCcases
+{
+  RC_ACTIVITY,
+  RC_ALL,
+  RC_AUTODETACH,
+  RC_BELL,
+  RC_BIND,
+  RC_BUFFERFILE,
+  RC_CHDIR,
+  RC_CRLF,
+  RC_ECHO,
+  RC_ESCAPE,
+  RC_FLOW,
+  RC_HARDCOPY_APP,
+  RC_HARDSTATUS,
+  RC_LOGIN,
+  RC_MARKKEYS,
+  RC_MODE,
+  RC_MONITOR,
+  RC_MSGMINWAIT,
+  RC_MSGWAIT,
+  RC_NETHACK,
+  RC_PASSWORD,
+  RC_POW_DETACH_MSG,
+  RC_REDRAW,
+  RC_REFRESH,
+  RC_SCREEN,
+  RC_SCROLLBACK,
+  RC_SHELL,
+  RC_SHELLAKA,
+  RC_SLEEP,
+  RC_SLOWPASTE,
+  RC_STARTUP_MESSAGE,
+  RC_TERM,
+  RC_TERMCAP,
+  RC_TERMINFO,
+  RC_VBELL,
+  RC_VBELL_MSG,
+  RC_VBELLWAIT,
+  RC_VISUALBELL,
+  RC_VISUALBELL_MSG,
+  RC_WRAP,
+  RC_RCEND
+};
+
+#ifdef UTMPOK
+static utmp, utmpf;
+static char UtmpName[] = UTMPFILE;
+# ifdef MIPS
+  static utmpfappend;
+# endif
+#endif
+
+static FILE *fp = NULL;
+static char *rc_name;
+
+char *SaveStr(str)
+register char *str;
+{
+  register char *cp;
+
+  if ((cp = malloc(strlen(str) + 1)) == NULL)
+    Msg_nomem;
+  else
+    strcpy(cp, str);
+  return cp;
+}
+
+static char *CatExtra(str1, str2)
+register char *str1, *str2;
+{
+  register char *cp;
+  register int len1, len2, add_colon;
+
+  len1 = strlen(str1);
+  if (len1 == 0)
+    return(str2);
+  add_colon = (str1[len1 - 1] != ':');
+  if (str2)
+    {
+      len2 = strlen(str2);
+      if ((cp = realloc(str2, (unsigned) len1 + len2 + add_colon + 1)) == NULL)
+       Msg_nomem;
+      bcopy(cp, cp + len1 + add_colon, len2 + 1);
+    }
+  else
+    {
+      if (len1 == 0)
+       return 0;
+      if ((cp = malloc((unsigned) len1 + add_colon + 1)) == NULL)
+       Msg_nomem;
+      cp[len1 + add_colon] = '\0'; 
+    }
+  bcopy(str1, cp, len1);
+  if (add_colon)
+    cp[len1] = ':';
+
+  return cp;
+}
+
+static char *findrcfile(rcfile)
+char *rcfile;
+{
+  static char buf[256];
+  char *rc, *p;
+
+  if (rcfile)
+    {
+      rc = SaveStr(rcfile);
+      debug1("findrcfile: you specified '%s'\n", rcfile);
+    }
+  else
+    {
+      debug("findrcfile: you specified nothing...\n");
+      if ((p = getenv("ISCREENRC")) != NULL && *p != '\0')
+       {
+         debug1("  ... but $ISCREENRC has: '%s'\n", p);
+         rc = SaveStr(p);
+       }
+      else if ((p = getenv("SCREENRC")) != NULL && *p != '\0')
+       {
+         debug1("  ... but $SCREENRC has: '%s'\n", p);
+         rc = SaveStr(p);
+       }
+      else
+       {
+         debug("  ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
+         if (strlen(home) > 244)
+           Msg(0, "Rc: home too large");
+         sprintf(buf, "%s/.iscreenrc", home);
+          if (access(buf, R_OK))
+           sprintf(buf, "%s/.screenrc", home);
+         rc = SaveStr(buf);
+       }
+    }
+  return rc;
+}
+
+/*
+ * this will be called twice:
+ * 1) rcfilename = "/etc/screenrc"
+ * 2) rcfilename = RcFileName
+ */
+void
+StartRc(rcfilename)
+char *rcfilename;
+{
+  register int argc, len;
+  register char *p, *cp;
+  char buf[256];
+  char *args[MAXARGS], *t;
+
+  rc_name = findrcfile(rcfilename);
+
+  if ((fp = secfopen(rc_name, "r")) == NULL)
+    {
+      if (RcFileName && strcmp(RcFileName, rc_name) == 0)
+       {
+          /*
+           * User explicitly gave us that name,
+           * this is the only case, where we get angry, if we can't read
+           * the file.
+           */
+         debug3("StartRc: '%s','%s', '%s'\n", RcFileName, rc_name, rcfilename);
+          Msg(0, "Unable to open \"%s\".", rc_name);
+         /* NOTREACHED */
+       }
+      debug1("StartRc: '%s' no good. ignored\n", rc_name);
+      Free(rc_name);
+      rc_name = "";
+      return;
+    }
+  if ((t = getenv("TERM")) == NULL)
+    Msg(0, "No TERM in environment.");
+  debug1("startrc got termcp:%s\n", t);
+  while (fgets(buf, sizeof buf, fp) != NULL)
+    {
+      if ((p = rindex(buf, '\n')) != NULL)
+       *p = '\0';
+      if ((argc = Parse(buf, args)) == 0)
+       continue;
+      if (strcmp(args[0], "echo") == 0)
+       {
+         if (argc < 2 || (argc == 3 && strcmp(args[1], "-n")) || argc > 3)
+           {
+             DeadlyMsg = 0;
+             Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
+           }
+         else
+           {
+             printf((argc == 3) ? "%s" : "%s\r\n", args[argc - 1]);
+           }
+       }
+      else if (strcmp(args[0], "sleep") == 0)
+       {
+         if (argc != 2)
+           {
+             DeadlyMsg = 0;
+             Msg(0, "%s: sleep: one numeric argument expected.", rc_name);
+           }
+         else
+           sleep(atoi(args[1]));
+       }
+#ifdef TERMINFO
+      else if (strcmp(args[0], "terminfo") == 0)
+#else
+      else if (strcmp(args[0], "termcap") == 0)
+#endif
+       {
+         if (argc < 3 || argc > 4)
+           Msg(0, "%s: %s: incorrect number of arguments.", rc_name, args[0]);
+         for (p = args[1]; p && *p; p = cp)
+           {
+             if ((cp = index(p, '|')) != 0)
+               *cp++ = '\0';
+             len = strlen(p);
+             if (p[len - 1] == '*')
+               {
+                 if (!(len - 1) || !strncmp(p, t, len - 1))
+                   break;
+               }
+             else if (!strcmp(p, t))
+               break;
+           }
+         if (!(p && *p))
+           continue;
+         extra_incap = CatExtra(args[2], extra_incap);
+         if (argc == 4)
+           extra_outcap = CatExtra(args[3], extra_outcap);
+       }
+    }
+  fclose(fp);
+  Free(rc_name);
+  rc_name = "";
+}
+
+static char *
+ParseChar(p, cp)
+char *p, *cp;
+{
+  if (*p == '^')
+    {
+      if (*++p == '?')
+        *cp = '\177';
+      else if (*p >= '@')
+        *cp = Ctrl(*p);
+      else
+        return 0;
+      ++p;
+    }
+  else if (*p == '\\' && *++p <= '7' && *p >= '0')
+    {
+      *cp = 0;
+      do
+        *cp = *cp * 8 + *p - '0';
+      while (*++p <= '7' && *p >= '0');
+    }
+  else
+    *cp = *p++;
+  return p;
+}
+
+/*
+ * CompileKeys must be called before Markroutine is first used.
+ * to initialise the keys with defaults, call CompileKeys(NULL, mark_key_tab);
+ *
+ * s is an ascii string in a termcap-like syntax. It looks like
+ *   "j=u:k=d:l=r:h=l: =.:" and so on...
+ * this example rebinds the cursormovement to the keys u (up), d (down),
+ * l (left), r (right). placing a mark will now be done with ".".
+ */
+int CompileKeys(s, array)
+char *s, *array;
+{
+  int i;
+  unsigned char key, value;
+
+  if (!s || !*s)
+    {
+      for (i = 0; i < 256; i++)
+        array[i] = i;
+      return 0;
+    }
+  while (*s)
+    {
+      s = ParseChar(s, (char *) &key);
+      if (*s != '=')
+       return -1;
+      do 
+       {
+          s = ParseChar(++s, (char *) &value);
+         array[value] = key;
+       }
+      while (*s == '=');
+      if (!*s) 
+       break;
+      if (*s++ != ':')
+       return -1;
+    }
+  return 0;
+}
+
+static char **SaveArgs(argc, argv)
+register int argc;
+register char **argv;
+{
+  register char **ap, **pp;
+
+  if ((pp = ap = (char **) malloc((unsigned) (argc + 1) * sizeof(char **))) == 0)
+    Msg_nomem;
+#ifdef notdef
+  debug("saveargs:\n"); 
+#endif
+  while (argc--)
+    {
+      debug1(" '%s'", *argv);
+      *pp++ = SaveStr(*argv++);
+    }
+  debug("\n");
+  *pp = 0;
+  return ap;
+}
+
+void
+FinishRc(rcfilename)
+char *rcfilename;
+{
+  /* in FinishRc screen is not yet open, thus Msg() is deadly here.
+   */
+  char buf[256];
+
+  rc_name = findrcfile(rcfilename);
+
+  if ((fp = secfopen(rc_name, "r")) == NULL)
+    {
+      if (RcFileName && strcmp(RcFileName, rc_name) == 0)
+       {
+         /*
+          * User explicitly gave us that name, 
+          * this is the only case, where we get angry, if we can't read
+          * the file.
+          */
+         debug3("FinishRc:'%s','%s','%s'\n", RcFileName, rc_name, rcfilename);
+          Msg(0, "Unable to open \"%s\".", rc_name);
+         /* NOTREACHED */
+       }
+      debug1("FinishRc: '%s' no good. ignored\n", rc_name);
+      Free(rc_name);
+      rc_name = "";
+      return;
+    }
+
+  debug("finishrc is going...\n");
+  while (fgets(buf, sizeof buf, fp) != NULL)
+    {
+      RcLine(buf);
+    }
+  (void) fclose(fp);
+  Free(rc_name);
+  rc_name = "";
+}
+
+/*
+ * this is a KEY_SET pressed
+ */
+void
+DoSet(argv)
+char **argv;
+{
+  char *p;
+  static char buf[256];
+
+  p = buf;
+  debug("DoSet\n");
+  if (!argv || !*argv || !**argv)
+    {
+      debug("empty DoSet\n");
+      sprintf(buf, "set ");
+      RcLine(buf);
+      return;
+    }
+  sprintf(p, "set"); p+=3;
+  while(*argv && (strlen(buf) + strlen(*argv) < 255))
+    {
+      sprintf(p, " %s", *argv++);
+      p += strlen(p);
+    }
+  RcLine(buf);
+}
+
+/*
+ *     "$HOST blafoo"          -> "localhost blafoo"
+ *     "${HOST}blafoo"         -> "localhostblafoo"
+ *     "\$HOST blafoo"         -> "$HOST blafoo"
+ *     "\\$HOST blafoo"        -> "\localhost blafoo"
+ *     "'$HOST ${HOST}'"       -> "'$HOST ${HOST}'" 
+ *     "'\$HOST'"              -> "'\$HOST'"
+ *     "\'$HOST' $HOST"        -> "'localhost' $HOST"
+ */
+static char *expand_env_vars(ss)
+char *ss;
+{
+  static char ebuf[2048];
+  register int esize = 2047, quofl = 0;
+  register char *e = ebuf;
+  register char *s = ss;
+  register char *v;
+
+  while (*s && *s != '\n' && esize > 0)
+    {
+      if (*s == '\'')
+       quofl ^= 1;
+      if (*s == '$' && !quofl)
+       {
+         char *p, c;
+
+         p = ++s;
+         if (*s == '{')
+           {
+             p = ++s;
+             while (*p != '}')
+               if (*p++ == '\0')
+                 return ss;
+           }
+         else
+           {
+             while (*p != ' ' && *p != '\0' && *p != '\n')
+               p++;
+           }
+         c = *p;
+         debug1("exp: c='%c'\n", c);
+         *p = '\0';
+         if (v = getenv(s)) 
+           {
+             debug2("exp: $'%s'='%s'\n", s, v);
+             while (*v && esize-- > 0)
+               *e++ = *v++;
+           }
+         else 
+           debug1("exp: '%s' not env\n", s);
+         if ((*p = c) == '}')
+           p++;
+         s = p;
+       }
+      else
+       {
+         if (s[0] == '\\' && !quofl)
+           if (s[1] == '$' || (s[1] == '\\' && s[2] == '$') ||
+               s[1] == '\'' || (s[1] == '\\' && s[2] == '\''))
+             s++;
+         *e++ = *s++;
+         esize--;
+       }
+    }
+  if (esize <= 0)
+    Msg(0, "expand_env_vars: buffer overflow\n");
+  *e = '\0';
+  return ebuf;
+}
+
+void
+RcLine(ubuf)
+char *ubuf;
+{
+  char *args[MAXARGS];
+  register char *buf, *p, **pp, **ap;
+  register int argc, setflag;
+  int q, qq;
+  char key;
+  int low, high, mid, x;
+
+  buf = expand_env_vars(ubuf); 
+
+  ap = args;
+
+  if ((p = rindex(buf, '\n')) != NULL)
+    *p = '\0';
+  if (strncmp("set ", buf, 4) == 0)
+    {
+      buf += 4;
+      setflag = 1;
+      debug1("RcLine: '%s' is a set command\n", buf);
+    }
+  else if (strncmp("se ", buf, 3) == 0)
+    {
+      buf += 3;
+      setflag = 1;
+      debug1("RcLine: '%s' is a se command\n", buf);
+    }
+  else
+    {
+      setflag = 0;
+      debug1("RcLine: '%s'\n", buf);
+    }
+  if ((argc = Parse(buf, ap)) == 0)
+    {
+      if (setflag)
+       {
+         DeadlyMsg = 0;
+         Msg(0, "%s: set what?\n", rc_name);
+       }
+      return;
+    }
+
+  low = 0;
+  high = (int)RC_RCEND - 1;
+  while (low <= high)
+    {
+      mid = (low + high) / 2;
+      x = strcmp(ap[0], RCNames[mid]);
+      if (x < 0)
+        high = mid - 1;
+      else if (x > 0)
+        low = mid + 1;
+      else
+        break;
+    }
+  if (low > high)
+    mid = (int)RC_RCEND;
+  switch ((enum RCcases) mid)
+    {
+    case RC_ESCAPE:
+      if (argc != 2 || !ParseEscape(ap[1]))
+       {
+         DeadlyMsg = 0; 
+         Msg(0, "%s: two characters required after escape.", rc_name);
+         return;
+       }
+      if (Esc != MetaEsc)
+       ktab[Esc].type = KEY_OTHER;
+      else
+       ktab[Esc].type = KEY_IGNORE;
+      return;
+    case RC_CHDIR:
+      if (setflag)
+       break;
+      p = argc < 2 ? home : ap[1];
+      if (chdir(p) == -1)
+       {
+         DeadlyMsg = 0; 
+         Msg(errno, "%s", p);
+       }
+      return;
+    case RC_SHELL:
+      ParseSaveStr(argc, ap, &ShellProg, "shell");
+      ShellArgs[0] = ShellProg;
+      return;
+    case RC_SHELLAKA:
+      ParseSaveStr(argc, ap, &shellaka, "shellaka");
+      return;
+    case RC_SCREEN:
+      if (setflag)
+       break;
+      DoScreen(rc_name, ap + 1);
+      return;
+    case RC_SLEEP:
+    case RC_TERMCAP:
+    case RC_TERMINFO:
+      return;                  /* Already handled */
+    case RC_TERM:
+      {
+        char *tmp = NULL;
+
+        ParseSaveStr(argc, ap, &tmp, "term");
+        if (!tmp)
+          return;
+       if (strlen(tmp) >= 20)
+         {
+           DeadlyMsg = 0;
+            Msg(0,"%s: term: argument too long ( < 20)", rc_name);
+            Free(tmp);
+           return;
+          }
+        strcpy(screenterm, args[1]);
+       Free(tmp);
+        debug1("screenterm set to %s\n", screenterm);
+        MakeTermcap(0);
+        return;        
+      }
+    case RC_ECHO:
+      if (HasWindow && *rc_name == '\0')
+       {
+         /*
+          * user typed ^A:echo... well, echo isn't FinishRc's job,
+          * but as he wanted to test us, we show good will
+          */
+         DeadlyMsg = 0;
+         if (argc == 2 || (argc == 3 && !strcmp(ap[1], "-n")))
+           Msg(0, "%s", ap[argc - 1]);
+         else
+           Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
+       }
+      return;
+    case RC_BELL:
+      ParseSaveStr(argc, ap, &BellString, "bell");
+      return;
+    case RC_BUFFERFILE:
+      ParseSaveStr(argc, ap, &BufferFile, "bufferfile");
+      return;
+    case RC_ACTIVITY:
+      ParseSaveStr(argc, ap, &ActivityString, "activity");
+      return;
+    case RC_POW_DETACH_MSG:
+      ParseSaveStr(argc, ap, &PowDetachString, "pow_detach");
+      return;
+    case RC_LOGIN:
+#ifdef UTMPOK
+      q = loginflag;
+      ParseOnOff(argc, ap, &loginflag);
+      if (fore && setflag)
+       {
+         SlotToggle(loginflag?(1):(-1));
+         loginflag = q;
+       }
+#endif
+      return;
+    case RC_FLOW:
+      if (argc == 3 && ap[2][0] == 'i')
+       {
+         iflag = 1;
+         argc--;
+       }
+      if (argc == 2 && ap[1][0] == 'a')
+       default_flow = FLOW_AUTOFLAG;
+      else
+       ParseOnOff(argc, ap, &default_flow);
+      return;
+    case RC_WRAP:
+      ParseOnOff(argc, ap, &wrap);
+      return;
+    case RC_HARDSTATUS:
+      ParseOnOff(argc, ap, &use_hardstatus);
+      if (use_hardstatus)
+       HS = termcapHS;
+      else
+       HS = 0;
+      return;
+    case RC_MONITOR:
+       {
+         int f; 
+
+         ParseOnOff(argc, ap, &f);
+         if (fore && setflag)
+           fore->monitor = (f == 0) ? MON_OFF : MON_ON;
+         else
+           default_monitor = (f == 0) ? MON_OFF : MON_ON;
+       }
+      return;
+    case RC_REDRAW:
+    case RC_REFRESH:
+       {
+         int r;
+
+         ParseOnOff(argc, ap, &r);
+         if (fore && setflag)
+           fore->norefresh = (r) ? 0 : 1;
+         else
+           {
+             all_norefresh = (r) ? 0 : 1;
+             if (all_norefresh)
+               Msg(0, "No refresh on window change!\n");
+             else
+               Msg(0, "Window specific refresh\n");
+           }
+       }
+      return;
+    case RC_VBELL:
+    case RC_VISUALBELL:
+      ParseOnOff(argc, ap, &visual_bell);
+      return;
+    case RC_VBELLWAIT:
+      ParseNum(argc, ap, &VBellWait);
+      if (fore && rc_name[0] == '\0')
+        Msg(0, "vbellwait set to %d seconds", VBellWait);
+      return;
+    case RC_MSGWAIT:
+      ParseNum(argc, ap, &MsgWait);
+      if (fore && rc_name[0] == '\0')
+        Msg(0, "msgwait set to %d seconds", MsgWait);
+      return;
+    case RC_MSGMINWAIT:
+      ParseNum(argc, ap, &MsgMinWait);
+      if (fore && rc_name[0] == '\0')
+        Msg(0, "msgminwait set to %d seconds", MsgMinWait);
+      return;
+    case RC_SCROLLBACK:
+      if (fore && setflag)
+       {
+         int i;
+
+         ParseNum(argc, ap, &i);
+         ChangeScrollback(fore, i, fore->width);
+         if (fore && rc_name[0] == '\0')
+           Msg(0, "scrollback set to %d", fore->histheight);
+       }
+      else
+       ParseNum(argc, ap, &default_histheight);
+      return;
+    case RC_SLOWPASTE:
+      ParseNum(argc, ap, &slowpaste);
+      if (fore && rc_name[0] == '\0')
+       Msg(0, "slowpaste set to %d milliseconds", slowpaste);
+      return;
+    case RC_MARKKEYS:
+      {
+        char *tmp = NULL;
+
+        ParseSaveStr(argc, ap, &tmp, "markkeys");
+        if (CompileKeys(ap[1], mark_key_tab))
+         {
+           DeadlyMsg = 0;
+           Msg(0, "%s: markkeys: syntax error.", rc_name);
+           Free(tmp);
+           return;
+         }
+        debug1("markkeys %s\n", ap[1]);
+        Free(tmp);
+        return;
+      }
+#ifdef NETHACK
+    case RC_NETHACK:
+      ParseOnOff(argc, ap, &nethackflag);
+      return;
+#endif
+    case RC_HARDCOPY_APP:
+      ParseOnOff(argc, ap, &hardcopy_append);
+      return;
+    case RC_VBELL_MSG:
+    case RC_VISUALBELL_MSG:
+      ParseSaveStr(argc, ap, &VisualBellString, "vbell_msg");
+      debug1(" new vbellstr '%s'\n", VisualBellString);
+      return;
+    case RC_MODE:
+      if (argc != 2)
+       {
+         DeadlyMsg = 0; 
+         Msg(0, "%s: mode: one argument required.", rc_name);
+         return;
+       }
+      if (!IsNum(ap[1], 7))
+       {
+         DeadlyMsg = 0; 
+         Msg(0, "%s: mode: octal number expected.", rc_name);
+         return;
+       }
+      (void) sscanf(ap[1], "%o", &TtyMode);
+      return;
+    case RC_CRLF:
+      ParseOnOff(argc, ap, &join_with_cr);
+      return;
+    case RC_AUTODETACH:
+      ParseOnOff(argc, ap, &auto_detach);
+      return;
+    case RC_STARTUP_MESSAGE:
+      ParseOnOff(argc, ap, &default_startup);
+      return;
+#ifdef PASSWORD
+    case RC_PASSWORD:
+      CheckPassword = 1;
+      if (argc >= 2)
+       {
+         strncpy(Password, ap[1], sizeof Password);
+         if (!strcmp(Password, "none"))
+           CheckPassword = 0;
+       }
+      else
+       {
+         char *mstr = 0;
+         int msleep = 0, st;
+          char salt[2];
+
+#ifdef POSIX
+         if (HasWindow)
+           {
+             Msg(0, "Cannot ask for password on POSIX systems");
+             return;
+           }
+#endif
+         /* there is a clear screen sequence in the buffer. */
+         fflush(stdout);
+         if (HasWindow)
+           {
+              ClearDisplay();
+             SetTTY(0, &OldMode);
+           }
+         strncpy(Password, getpass("New screen password:"),
+                 sizeof(Password));
+         if (strcmp(Password, getpass("Retype new password:")))
+           {
+#ifdef NETHACK
+              if (nethackflag)
+               mstr = "[ Passwords don't match - your armor crumbles away ]";
+             else
+#endif
+             mstr = "[ Passwords don't match - checking turned off ]";
+             msleep = 1;
+             CheckPassword = 0;
+           }
+         if (Password[0] == '\0')
+           {
+             CheckPassword = 0;
+             mstr = "[ No password - no secure ]";
+             msleep = 1;
+           }
+         for (st=0; st<2; st++)
+            salt[st] = 'A' + (int)((time(0) >> 6*st) % 26);
+         strncpy(Password, crypt(Password, salt), sizeof(Password));
+         if (CheckPassword)
+           {
+#ifdef COPY_PASTE
+             if (copybuffer)
+
+               Free(copybuffer);
+             copylen = strlen(Password);
+             if ((copybuffer = (char *) malloc(copylen+1)) == NULL)
+               {
+                 Msg_nomem;
+                 return;
+               }
+             strcpy(copybuffer, Password);
+             mstr = "[ Password moved into copybuffer ]";
+             msleep = 1;
+#else                          /* COPY_PASTE */
+             mstr = "[ Crypted password is \"%s\" ]";
+             msleep = 5;
+#endif                         /* COPY_PASTE */
+           }
+          if (HasWindow)
+           {
+             SetTTY(0, &NewMode);
+             Activate(0); /* Redraw */
+             if (mstr)
+               {
+                 Msg(0, mstr, Password);
+               }
+           }
+          else
+           {
+             if (mstr)
+               {
+                 printf(mstr, Password);
+                 putchar('\n');
+                 sleep(msleep);
+               }
+              ClearDisplay();
+           }
+       }
+      debug1("finishrc: our password is: --%s%-- \n", Password);
+      return;
+#endif                         /* PASSWORD */
+    case RC_ALL:
+      if (!setflag || !HasWindow || *rc_name)
+        break;
+      display_help();
+      return;
+    case RC_BIND:
+      if (setflag)
+       break;
+      p = ap[1];
+      if (argc < 2 || *p == '\0')
+       {
+         DeadlyMsg = 0; 
+         Msg(0, "%s: key expected after bind.", rc_name);
+         return;
+       }
+      if ((p = ParseChar(p, &key)) == NULL || *p)
+       {
+         DeadlyMsg = 0; 
+         Msg(0, "%s: bind: character, ^x, or (octal) \\032 expected.",
+             rc_name);
+         return;
+       }
+      if (ktab[key].type != KEY_IGNORE)
+       {
+         ktab[key].type = KEY_IGNORE;
+         if ((pp = ktab[key].args) != NULL)
+           {
+             for (; *pp; pp++)
+               Free(*pp);
+             Free(ktab[key].args);
+           }
+       }
+      if (argc > 2)
+       {
+         for (pp = KeyNames; *pp; ++pp)
+           if (strcmp(ap[2], *pp) == 0)
+             break;
+         if (*pp)
+           {
+             ktab[key].type = (enum keytype) (pp - KeyNames + 1);
+             if (argc > 3)
+               {
+                 ktab[key].args = SaveArgs(argc - 3, ap + 3);
+               }
+             else
+               ktab[key].args = NULL;
+           }
+         else
+           {
+             ktab[key].type = KEY_CREATE;
+             ktab[key].args = SaveArgs(argc - 2, ap + 2);
+           }
+       }
+      return;
+    case RC_RCEND:
+    default:
+       {
+         char ibuf[3];
+         /*
+          * now we are user-friendly: 
+          * if anyone typed a key name like "help" or "next" ...
+          * we did not match anything above. so look in the KeyNames table.
+          */
+         debug1("--ap[0] %s\n", ap[0]);
+         for (pp = KeyNames; *pp; ++pp)
+           if (strcmp(ap[0], *pp) == 0)
+               break;
+         if (*pp == 0)
+           break;
+
+         ibuf[0] = Esc;
+         ibuf[1] = pp - KeyNames +1;
+         debug1("RcLine: it was a keyname: '%s'\n", *pp);
+         q = 2; qq = 0;
+         if (HasWindow)
+           ProcessInput(ibuf, &q, (char *)0, &qq, 0);
+         else
+           {
+             DeadlyMsg = 0; 
+             Msg(0, "%s: Key '%s' has no effect while no window open...\n",
+                 rc_name, ap[0]);
+           }
+       }
+      return;
+    }
+  DeadlyMsg = 0; 
+  Msg(0, "%s: unknown %skeyword \"%s\"", rc_name, 
+      setflag?"'set' ":"", ap[0]);
+}
+
+static int 
+Parse(buf, args)
+char *buf, **args;
+{
+  register char *p = buf, **ap = args;
+  register int delim, argc;
+
+  argc = 0;
+  for (;;)
+    {
+      while (*p && (*p == ' ' || *p == '\t'))
+       ++p;
+      if (*p == '\0' || *p == '#')
+       {
+         *p = '\0';
+         return argc;
+       }
+      if (argc > MAXARGS - 1)
+       Msg(0, "%s: too many tokens.", rc_name);
+      delim = 0;
+      if (*p == '"' || *p == '\'')
+       delim = *p++;
+      argc++;
+      *ap = p;
+      *++ap = 0;
+      while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
+       ++p;
+      if (*p == '\0')
+       {
+         if (delim)
+           {
+             DeadlyMsg = 0;
+             Msg(0, "%s: Missing quote.", rc_name);
+             return 0;
+       }
+         return argc;
+       }
+      *p++ = '\0';
+    }
+}
+
+int 
+ParseEscape(p)
+char *p;
+{
+  if ((p = ParseChar(p, &Esc)) == NULL ||
+      (p = ParseChar(p, &MetaEsc)) == NULL || *p)
+    return 0;
+  return 1;
+}
+
+static void
+ParseNum(argc, ap, var)
+int argc;
+char *ap[];
+int *var;
+{
+  int i;
+  char *p;
+
+  if (argc == 2 && ap[1][0] != '\0')
+    {
+      i = 0; 
+      p = ap[1];
+      while (*p)
+       {
+         if (*p >= '0' && *p <= '9')
+           i = 10 * i + (*p - '0');
+         else
+           {
+             DeadlyMsg = 0;
+             Msg(0, "%s: %s: invalid argument. Give numeric argument",
+                 rc_name, ap[0]);
+             return;
+           }    
+         p++;
+       }
+    }
+  else
+    {
+      DeadlyMsg = 0;
+      Msg(0, "%s: %s: invalid argument. Give one argument",
+          rc_name, ap[0]);
+      return;
+    }
+  debug1("ParseNum got %d\n", i);
+  *var = i;
+}
+
+static void
+ParseSaveStr(argc, ap, var, title)
+int argc;
+char *ap[];
+char **var;
+char *title;
+{
+  if (argc != 2)
+    {
+      DeadlyMsg = 0;
+      Msg(0, "%s: %s: one argument required.", rc_name, title);
+      return;
+    }
+  if (*var)
+    Free(*var);
+  *var = SaveStr(ap[1]);
+  return;
+}
+static void
+ParseOnOff(argc, ap, var)
+int argc;
+char *ap[];
+int *var;
+{
+  register int num = -1;
+
+  if (argc == 2 && ap[1][0] == 'o')
+    {
+      if (ap[1][1] == 'f')
+       num = 0;
+      else if (ap[1][1] == 'n')
+       num = 1;
+    }
+  if (num < 0)
+    {
+      DeadlyMsg = 0;
+      Msg(0, "%s: %s: invalid argument. Give 'on' or 'off'", rc_name, ap[0]);
+      return;
+    }
+  *var = num;
+}
+
+
+static int IsNum(s, base)
+register char *s;
+register int base;
+{
+  for (base += '0'; *s; ++s)
+    if (*s < '0' || *s > base)
+      return 0;
+  return 1;
+}
+
+static int IsNumColon(s, base, p, psize)
+int base, psize;
+char *s, *p;
+{
+  char *q;
+  if ((q = rindex(s, ':')) != NULL)
+    {
+      strncpy(p, q + 1, psize - 1);
+      p[psize - 1] = '\0';
+      *q = '\0';
+    }
+  else
+    *p = '\0';
+  return IsNum(s, base);
+}
+
+void
+SlotToggle(how)
+int how;
+/*
+ * how = 0     real toggle mode
+ * how > 0     do try to set a utmp slot.
+ * how < 0     try to withdraw a utmp slot
+ *
+ * slot = -1    window not logged in.
+ * slot = 0     window not logged in, but should be logged in. 
+ *              (unable to write utmp, or detached).
+ */
+{
+  debug1("SlotToggle %d\n", how);
+  if (how == 0)
+    how = (fore->slot == (slot_t) -1)?(1):(-1);
+    /* 
+     * slot 0 or active -> we try to log out.
+     * slot -1          -> we try to log in.
+     */
+#ifdef UTMPOK
+  if (how > 0)
+    {
+      debug(" try to log in\n");
+      if ((fore->slot == (slot_t) -1) || (fore->slot == (slot_t) 0))
+       {
+#ifdef USRLIMIT
+          if (CountUsers() >= USRLIMIT)
+            Msg(0, "User limit reached.");
+          else
+#endif
+            {
+              if (SetUtmp(fore, ForeNum) == 0)
+                Msg(0, "This window is now logged in.");
+              else
+                Msg(0, "This window should now be logged in.");
+            }
+       }
+      else
+       Msg(0, "This window is already logged in.");
+    }
+  else if (how < 0)
+    {
+      debug(" try to log out\n");
+      if (fore->slot == (slot_t) -1)
+       Msg(0, "This window is already logged out\n");
+      else if (fore->slot == (slot_t) 0)
+       {
+         debug("What a relief! In fact, it was not logged in\n");
+         Msg(0, "This window is not logged in.");
+         fore->slot = (slot_t) -1;
+       }
+      else
+       {
+         RemoveUtmp(fore);
+         if (fore->slot != (slot_t) -1)
+           Msg(0, "What? Cannot remove Utmp slot?");
+         else
+           Msg(0, "This window is no longer logged in.");
+       }
+    }
+#else  /* !UTMPOK */
+  Msg(0, "Unable to modify %s.\n", UTMPFILE);
+#endif
+}
+
+void
+DoScreen(fn, av)
+char *fn, **av;
+{
+  register int flowflag, num, lflag = loginflag, aflag = 0;
+  register char *aka = NULL;
+  register int histheight = default_histheight;
+  char buf[20];
+  char termbuf[25];
+  char *termp;
+  char *args[2];
+
+  flowflag = default_flow;
+  termbuf[0] = '\0';
+  termp = NULL;
+  while (av && *av && av[0][0] == '-')
+    {
+      switch (av[0][1])
+       {
+       case 'f':
+         switch (av[0][2])
+           {
+           case 'n':
+           case '0':
+             flowflag = FLOW_NOW * 0;
+             break;
+           case 'y':
+           case '1':
+           case '\0':
+             flowflag = FLOW_NOW * 1;
+             break;
+           case 'a':
+             flowflag = FLOW_AUTOFLAG;
+             break;
+           default:
+             break;
+           }
+         break;
+       case 'k':
+       case 't':
+         if (av[0][2])
+           aka = &av[0][2];
+         else if (*++av)
+           aka = *av;
+         else
+           --av;
+         break;
+       case 'T':
+         if (av[0][2])
+           termp = &av[0][2];
+         else if (*++av)
+           termp = *av;
+         else
+           --av;
+         break;
+       case 'h':
+         if (av[0][2])
+           histheight = atoi(av[0] + 2);
+         else if (*++av)
+           histheight = atoi(*av);
+         else 
+           --av;
+         break;
+       case 'l':
+         switch (av[0][2])
+           {
+           case 'n':
+           case '0':
+             lflag = 0;
+             break;
+           case 'y':
+           case '1':
+           case '\0':
+             lflag = 1;
+             break;
+           default:
+             break;
+           }
+         break;
+       case 'a':
+         aflag = 1;
+         break;
+       default:
+         Msg(0, "%s: screen: invalid option -%c.", fn, av[0][1]);
+         break;
+       }
+      ++av;
+    }
+  num = 0;
+  if (av && *av && IsNumColon(*av, 10, buf, sizeof(buf)))
+    {
+      if (*buf != '\0')
+       aka = buf;
+      num = atoi(*av);
+      if (num < 0 || num > MAXWIN - 1)
+       {
+         Msg(0, "%s: illegal screen number %d.", fn, num);
+         num = 0;
+       }
+      ++av;
+    }
+  if (!av || !*av)
+    {
+      av = args;
+      av[0] = ShellProg;
+      av[1] = NULL;
+      if (!aka)
+       aka = shellaka;
+    }
+  MakeWindow(aka, av, aflag, flowflag, num, (char *) 0, lflag, histheight, termp);
+}
+
+void
+WriteFile(dump)
+int dump;
+{
+  /* dump==0:  create .termcap,
+   * dump==1:  hardcopy,
+   * #ifdef COPY_PASTE
+   * dump==2:  BUFFERFILE
+   * #endif COPY_PASTE 
+   */
+  register int i, j, k;
+  register char *p;
+  register FILE *f;
+  char fn[1024];
+  char *mode = "w";
+
+  switch (dump)
+    {
+    case DUMP_TERMCAP:
+      i = SockNamePtr - SockPath;
+      strncpy(fn, SockPath, i);
+      strcpy(fn + i, ".termcap");
+      break;
+    case DUMP_HARDCOPY:
+      sprintf(fn, "hardcopy.%d", ForeNum);
+      if (hardcopy_append && !access(fn, W_OK))
+       mode = "a";
+      break;
+    case DUMP_EXCHANGE:
+      sprintf(fn, "%s", BufferFile);
+      umask(0);
+      break;
+    }
+
+  debug2("WriteFile(%d) %s\n", dump, fn);
+  if (UserContext() > 0)
+    {
+      debug("Writefile: usercontext\n");
+      if ((f = fopen(fn, mode)) == NULL)
+       {
+         debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn, mode);
+         UserReturn(0);
+       }
+      else
+       {
+         switch (dump)
+           {
+           case DUMP_HARDCOPY:
+             if (*mode == 'a')
+               {
+                 putc('>', f);
+                 for (j = screenwidth - 2; j > 0; j--)
+                   putc('=', f);
+                 fputs("<\n", f);
+               }
+             for (i = 0; i < screenheight; ++i)
+               {
+                 p = fore->image[i];
+                 for (k = screenwidth - 1; k >= 0 && p[k] == ' '; --k)
+                   ;
+                 for (j = 0; j <= k; ++j)
+                   putc(p[j], f);
+                 putc('\n', f);
+               }
+             break;
+           case DUMP_TERMCAP:
+             if ((p = index(MakeTermcap(fore->aflag), '=')) != NULL)
+               {
+                 fputs(++p, f);
+                 putc('\n', f);
+               }
+             break;
+#ifdef COPY_PASTE
+           case DUMP_EXCHANGE:
+             p = copybuffer;
+             for (i = 0; i < copylen; i++)
+               putc(*p++, f);
+             break;
+#endif
+           }
+         (void) fclose(f);
+         UserReturn(1);
+       }
+    }
+  if (UserStatus() <= 0)
+    Msg(0, "Cannot open \"%s\"", fn);
+  else
+    {
+      switch (dump)
+       {
+       case DUMP_TERMCAP:
+         Msg(0, "Termcap entry written to \"%s\".", fn);
+         break;
+       case DUMP_HARDCOPY:
+         Msg(0, "Screen image %s to \"%s\".",
+             (*mode == 'a') ? "appended" : "written", fn);
+         break;
+#ifdef COPY_PASTE
+       case DUMP_EXCHANGE:
+         Msg(0, "Copybuffer written to \"%s\".", fn);
+#endif
+       }
+    }
+}
+
+#ifdef COPY_PASTE
+
+void
+ReadFile()
+{
+  int i, l, size;
+  char fn[1024], c;
+  struct stat stb;
+
+  sprintf(fn, "%s", BufferFile);
+  debug1("ReadFile(%s)\n", fn);
+  if ((i = secopen(fn, O_RDONLY, 0)) < 0)
+    {
+      Msg(errno, "no %s -- no slurp", fn);
+      return;
+    }
+  if (fstat(i, &stb))
+    {
+      Msg(errno, "no good %s -- no slurp", fn);
+      close(i);
+      return;
+    }
+  size = stb.st_size;
+  if (copybuffer)
+    Free(copybuffer);
+  copylen = 0;
+  if ((copybuffer = malloc(size)) == NULL)
+    {
+      close(i);
+      Msg_nomem;
+      return;
+    }
+  errno = 0;
+  if ((l = read(i, copybuffer, size)) != size)
+    {
+      copylen = (l > 0) ? l : 0;
+#ifdef NETHACK
+      if (nethackflag)
+        Msg(errno, "You choke on your food: %d bytes", copylen);
+      else
+#endif
+      Msg(errno, "Got only %d bytes from %s", copylen, fn);
+      close(i);
+      return;
+    }
+  copylen = l;
+  if (read(i, &c, 1) > 0)
+    Msg(0, "Slurped only %d characters into buffer - try again", copylen);
+  else
+    Msg(0, "Slurped %d characters into buffer", copylen);
+  close(i);
+  return;
+}
+
+void
+KillBuffers()
+{
+  char fn[1024];
+  sprintf(fn, "%s", BufferFile);
+  errno = 0;
+  if (access(fn, W_OK) == -1)
+    {
+      Msg(errno, "%s not removed", fn);
+      return;
+    }
+  else
+    {
+      unlink(fn);
+      Msg(errno, "%s removed", fn);
+    }
+}
+#endif /* COPY_PASTE */
+
+#ifdef USRLIMIT
+CountUsers()
+{
+#ifdef GETUTENT
+  struct utmp *ut, *getutent();
+#else
+  struct utmp utmpbuf;
+#endif
+  int UserCount;
+
+  debug1("CountUsers() - utmp=%d\n",utmp);
+  if (!utmp)
+    return(0);
+  UserCount = 0;
+#ifdef GETUTENT
+  setutent();
+  while (ut = getutent())
+    if (ut->ut_type == USER_PROCESS)
+      UserCount++;
+#else
+  (void) lseek(utmpf, (off_t) 0, 0);
+  while (read(utmpf, &utmpbuf, sizeof(struct utmp)) > 0)
+    {
+      if (utmpbuf.ut_name[0] != '\0')
+       UserCount++;
+    }
+#endif
+  return(UserCount);
+}
+#endif
+
+#ifdef UTMPOK
+
+static slot_t loginslot;
+static struct utmp utmp_logintty;
+#ifdef _SEQUENT_
+static char loginhost[100+1];
+#endif
+
+void
+InitUtmp()
+{
+  debug("InitUtmp testing...\n");
+  if ((utmpf = open(UtmpName, O_RDWR)) == -1)
+    {
+      if (errno != EACCES)
+       Msg(errno, UtmpName);
+      debug("InitUtmp failed.\n");
+      utmp = 0;
+      return;
+    }
+#ifdef GETUTENT
+  close(utmpf);
+  utmpf= -1;
+#endif
+#ifdef MIPS
+  if ((utmpfappend = open(UtmpName, O_APPEND)) == -1) 
+    {
+      if (errno != EACCES)
+       Msg(errno, UtmpName);
+      return;
+    }
+#endif
+  utmp = 1;
+#ifndef apollo
+  ReInitUtmp();
+#endif
+}
+
+void
+ReInitUtmp()
+{
+#ifndef apollo
+  if (!utmp)
+    {
+      debug("Reinitutmp: utmp == 0\n");
+      return;
+    }
+#endif
+  debug("(Re)InitUtmp: removing your logintty\n");
+  loginslot = TtyNameSlot(display_tty);
+  if (loginslot!=(slot_t)0 && loginslot!=(slot_t)-1)
+    {
+#ifdef _SEQUENT_
+      if (p=ut_find_host(loginslot))
+        strncpy(loginhost, p, 100);
+#endif
+      RemoveLoginSlot(loginslot, &utmp_logintty);
+    }
+  debug1(" slot %d zapped\n", loginslot);
+}
+
+void
+RestoreLoginSlot()
+{
+  debug("RestoreLoginSlot()\n");
+#ifdef apollo
+  InitUtmp();
+#endif
+  if (utmp && loginslot!=(slot_t)0 && loginslot!=(slot_t)-1)
+    {
+#ifdef GETUTENT
+# ifdef _SEQUENT_
+      int fail;
+      debug1(" logging you in again (slot %s)\n", loginslot);
+/*
+ * We have problems if we add the console and use ut_add_user()
+ * because the id will be 'scon' instead of 'co'. So we
+ * restore it with pututline(). The reason why we don't use
+ * pututline all the time is that we want to set the host field.
+ * Unfortunatelly this can only be done with ut_add_user().
+ */
+      if (*loginhost)
+        {
+          fail = (ut_add_user(LoginName, loginslot, utmp_logintty.ut_pid,
+                              *loginhost?loginhost:(char *)0) == 0);
+        }
+      else
+        {
+          setutent();
+          fail = (pututline(&utmp_logintty) == 0);
+        }
+      if (fail)
+# else /* _SEQUENT_ */
+      debug1(" logging you in again (slot %s)\n", loginslot);
+      setutent();
+      if (pututline(&utmp_logintty)==0)
+# endif        /* _SEQUENT */
+#else  /* GETUTENT */
+      debug1(" logging you in again (slot %d)\n", loginslot);
+# ifdef sequent
+      /* call sequent undocumented routine to count logins and add utmp entry if possible */
+      if (add_utmp(loginslot, &utmp_logintty) == -1)
+# else
+      (void) lseek(utmpf, (off_t) (loginslot * sizeof(struct utmp)), 0);
+      if (write(utmpf, (char *) &utmp_logintty, sizeof(struct utmp))
+         != sizeof(struct utmp))
+# endif /* sequent */
+#endif /* GETUTENT */
+        {
+#ifdef NETHACK
+          if (nethackflag)
+            Msg(errno, "%s is too hard to dig in.", UTMPFILE);
+         else
+#endif
+          Msg(errno,"Could not write %s.", UTMPFILE);
+        }
+    }
+#ifdef apollo
+  close(utmpf);
+#endif
+  loginslot = (slot_t) 0;
+}
+
+void
+RemoveLoginSlot(slot, up)
+slot_t slot;
+struct utmp *up;
+{
+#ifdef GETUTENT
+  struct utmp *uu;
+#endif
+  struct utmp u;
+#ifdef apollo
+  struct utmp *uq;
+#endif
+
+#ifdef GETUTENT
+  debug2("RemoveLoginSlot(%s, %08x)\n", (slot == (slot_t) 0 ||
+         slot == (slot_t) -1 ) ? "no slot" : slot, up);
+#else
+  debug2("RemoveLoginSlot(%d, %08x)\n", slot, up);
+#endif
+#ifdef apollo
+  InitUtmp();
+  bzero((char *)up, sizeof(struct utmp));
+  uq = (struct utmp *)malloc(sizeof(struct utmp));
+  bzero((char *)uq, sizeof(struct utmp));
+#endif /* apollo */
+  if (!utmp)
+    return;
+  if (slot != (slot_t) 0 && slot != (slot_t) -1)
+    {
+      bzero((char *) &u, sizeof u);
+#ifdef GETUTENT
+      setutent();
+      strncpy(u.ut_line, slot, sizeof(u.ut_line));
+      if ((uu = getutline(&u)) == 0)
+        {
+         DeadlyMsg = 0;
+          Msg(0, "Utmp slot not found -> not removed");
+          return;
+        }
+      *up= *uu;
+# ifdef _SEQUENT_
+      if (ut_delete_user(slot, uu->ut_pid, 0, 0) == 0)
+# else
+      uu->ut_type = DEAD_PROCESS;
+      uu->ut_exit.e_termination = 0;
+      uu->ut_exit.e_exit= 0;
+      if (pututline(uu) == 0)
+# endif
+#else
+      (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
+      if (read(utmpf, (char *) up, sizeof u) != sizeof u)
+       {
+         DeadlyMsg = 0;
+         Msg(errno, "cannot read %s ???", UTMPFILE);
+         sleep(1);
+       }
+      (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
+# ifdef apollo
+      bcopy((char *)up, (char *)uq, sizeof(struct utmp));
+      bzero(uq->ut_name, sizeof(uq->ut_name));
+      bzero(uq->ut_host, sizeof(uq->ut_host));
+      if (write(utmpf, (char *)uq, sizeof(struct utmp)) != sizeof(struct utmp))
+# else
+      if (write(utmpf, (char *) &u, sizeof u) != sizeof u)
+# endif /* apollo */
+#endif
+        {
+#ifdef NETHACK
+          if (nethackflag)
+           {
+             DeadlyMsg = 0;
+              Msg(errno, "%s is too hard to dig in.", UTMPFILE); 
+           }
+          else
+#endif
+           {
+             DeadlyMsg = 0;
+              Msg(errno, "Could not write %s.", UTMPFILE);
+           }
+        }
+    }
+  else 
+    {
+      debug1("There is no utmp-slot to be removed(%d)\n", slot);
+    }
+#ifdef apollo
+  close(utmpf);
+  free(uq);
+#endif
+}
+
+char *
+stripdev(nam)
+char *nam;
+{
+#ifdef apollo
+  char *p;
+
+  if (nam == NULL)
+    return NULL;
+  if (p = strstr(nam,"/dev/"))
+    return p + 5;
+#else
+  if (nam == NULL)
+    return NULL;
+  if (strncmp(nam, "/dev/", 5) == 0)
+    return nam + 5;
+#endif
+  return nam;
+}
+
+static slot_t TtyNameSlot(nam)
+char *nam;
+{
+  char *name;
+  register slot_t slot;
+#ifndef GETUTENT
+  register struct ttyent *tp;
+#endif
+#ifdef apollo
+  struct utmp *up;
+#endif
+
+  debug1("TtyNameSlot(%s)\n", nam);
+#ifdef apollo
+  InitUtmp();
+#endif
+  if (!utmp || nam == NULL)
+    return (slot_t)0;
+  name = stripdev(nam);
+#ifdef GETUTENT
+  slot = name;
+#else
+# ifdef apollo
+  slot = 0;
+  up = (struct utmp *)malloc(sizeof(struct utmp));
+  while (1)
+    {
+      if ((read(utmpf, (char *)up, sizeof(struct utmp)) ==
+          sizeof(struct utmp)) && (strcmp(up->ut_line, name)))
+       slot++;
+      else
+       break;
+    }
+  close(utmpf);
+  free(up);
+# else /* !apollo */
+  slot = 1;
+  setttyent();
+  while ((tp = getttyent()) != NULL && strcmp(name, tp->ty_name) != 0)
+    {
+      debug2("'%s' %d, ", tp->ty_name, slot);
+      ++slot;
+    }
+  debug("\n");
+#  ifdef MIPS
+  if (tp == NULL)
+    {
+      slot = CreateUtmp(name);
+    }
+#  endif /* MIPS */
+# endif /* apollo */
+#endif /* GETUTENT */
+  return slot;
+}
+
+int
+SetUtmp(wi, displaynumber)
+struct win *wi;
+int displaynumber;
+{
+  register char *p;
+  register slot_t slot;
+  char *line;
+  struct utmp u;
+#ifdef UTHOST
+# ifdef _SEQUENT_
+  char host[100+5];
+# else
+  char host[sizeof(utmp_logintty.ut_host)+5];
+# endif
+#endif
+
+  wi->slot = (slot_t) 0;
+  if (!utmp)
+    return -1;
+  if ((slot = TtyNameSlot(wi->tty)) == (slot_t) NULL)
+    {
+      debug1("SetUtmp failed (tty %s).\n",wi->tty);
+      return -1;
+    }
+  debug2("SetUtmp %d will get slot %d...\n", displaynumber, (int)slot);
+#ifdef apollo
+  InitUtmp();
+#endif
+
+#ifdef UTHOST
+  host[sizeof(host)-5] = '\0';
+# ifdef _SEQUENT_
+  strncpy(host, loginhost, sizeof(host) - 5);
+# else
+  strncpy(host, utmp_logintty.ut_host, sizeof(host) - 5);
+# endif
+  if (loginslot != (slot_t)0 && loginslot != (slot_t)-1 && host[0] != '\0')
+    {
+      /*
+       * we want to set our ut_host field to something like
+       * ":ttyhf:s.0" or
+       * "faui45:s.0" or
+       * "132.199.81.4:s.0" (even this may hurt..), but not
+       * "faui45.informati"......:s.0
+       */
+      for (p = host; *p; p++)
+       {
+         if ((*p < '0' || *p > '9') && (*p != '.'))
+           break;
+       }
+      if (*p)
+       {
+         for (p = host; *p; p++)
+           {
+             if (*p == '.')
+               {
+                 *p = '\0';
+                 break;
+               }
+           }
+       }
+    }
+  else
+    {
+      strncpy(host + 1, stripdev(display_tty), sizeof(host) - 6);
+      host[0] = ':';
+    }
+  debug1("rlogin hostname: '%s'\n", host);
+  sprintf(host + strlen(host), ":S.%c", '0' + displaynumber);
+  debug1("rlogin hostname: '%s'\n", host);
+#endif /* UTHOST */
+
+  line = stripdev(wi->tty);
+  bzero((char *) &u, sizeof u);
+
+#ifdef GETUTENT
+# ifdef _SEQUENT_
+  if (ut_add_user(LoginName, slot, wi->wpid, host)==0)
+# else
+  strncpy(u.ut_user, LoginName, sizeof(u.ut_user));
+  strncpy(u.ut_id, line + strlen(line) - 2, sizeof(u.ut_id));
+  strncpy(u.ut_line, line, sizeof(u.ut_line));
+  u.ut_pid = wi->wpid;
+  u.ut_type = USER_PROCESS;
+#  ifdef SVR4
+    (void) time(&u.ut_tv.tv_sec);
+    u.ut_tv.tv_usec=0;
+#  else
+    (void) time(&u.ut_time);
+#  endif /* SVR4 */
+#  ifdef UTHOST
+  strncpy(u.ut_host, host, sizeof(u.ut_host));
+#  endif /* UTHOST */
+  if (pututline(&u) == 0)
+# endif /* _SEQUENT_ */
+#else  /* GETUTENT */
+  strncpy(u.ut_line, line, sizeof(u.ut_line));
+  strncpy(u.ut_name, LoginName, sizeof(u.ut_name));
+# ifdef UTHOST
+  strncpy(u.ut_host, host, sizeof(u.ut_host));
+# endif        /* UTHOST */
+# ifdef MIPS
+  u.ut_type = 7; /* USER_PROCESS */
+  strncpy(u.ut_id, line + 3, 4);
+# endif /* MIPS */
+  (void) time(&u.ut_time);
+# ifdef sequent
+/* call sequent undocumented routine to count logins and add utmp entry if possible */
+  if (add_utmp(slot, &u) == -1)
+# else
+  (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
+  if (write(utmpf, (char *) &u, sizeof u) != sizeof u)
+# endif /* sequent */
+#endif /* GETUTENT */
+
+    {
+#ifdef NETHACK
+      if (nethackflag)
+        Msg(errno, "%s is too hard to dig in.", UTMPFILE);
+      else
+#endif
+      Msg(errno,"Could not write %s.", UTMPFILE);
+#ifdef apollo
+      close(utmpf);
+#endif
+      return -1;
+    }
+  debug("SetUtmp successful\n");
+  wi->slot = slot;
+#ifdef apollo
+  close(utmpf);
+#endif
+  return 0;
+}
+
+#ifdef MIPS
+
+#define GETTTYENT
+static int ttyfd = 0;
+
+static void setttyent()
+{
+  if (ttyfd)
+    close(ttyfd);
+  ttyfd = open(UtmpName, O_RDONLY);
+}
+
+static struct ttyent *getttyent()
+{
+  static struct utmp u;
+  static struct ttyent t;
+
+  if (!ttyfd)
+    return NULL;
+  
+  if (read(ttyfd, &u, sizeof u)) 
+    {
+      t.ty_name = u.ut_line;
+      return &t;
+    }
+  return NULL;
+}
+
+CreateUtmp(name)
+char *name;
+{
+  int slot;
+  struct utmp u;
+
+  strncpy(u.ut_line, name, 8);
+  strncpy(u.ut_name, LoginName, 8);
+  u.ut_type = 7; /* USER_PROCESS */
+  strncpy(u.ut_id, name+3, 4);
+  (void) time(&u.ut_time);
+  slot = (lseek(utmpfappend, 0, 2) + 1) / sizeof u;
+  (void) write(utmpfappend, (char *)&u, sizeof u);
+  close(utmpfappend);
+  if ((utmpfappend = open(UtmpName, O_APPEND)) == -1) 
+    {
+      if (errno != EACCES)
+        Msg(errno, UtmpName);
+      return;
+    }
+  return slot;
+}
+#endif /* MIPS */
+
+/*
+ * if slot could be removed or was 0,  wi->slot = -1;
+ * else not changed.
+ */
+int
+RemoveUtmp(wi)
+struct win *wi;
+{
+#ifdef GETUTENT
+  struct utmp *uu;
+#endif
+#ifdef apollo
+  struct utmp *up;
+#endif
+  struct utmp u;
+  slot_t slot;
+
+  slot = wi->slot;
+#ifdef GETUTENT
+  debug1("RemoveUtmp(%s)\n", (slot == (slot_t) 0) ?
+         "no slot (0)":((slot == (slot_t) -1) ? "no slot (-1)" : slot));
+#else
+  debug1("RemoveUtmp(wi.slot: %d)\n", slot);
+#endif
+#ifdef apollo
+  InitUtmp();
+  up = (struct utmp *)malloc(sizeof(struct utmp));
+  bzero((char *)up, sizeof(struct utmp));
+#endif /* apollo */
+  if (!utmp)
+    return -1;
+  if (slot == (slot_t) 0 || slot == (slot_t) -1)
+    {
+      debug1("There is no utmp-slot to be removed(%d)\n", slot);
+      wi->slot = (slot_t) -1;
+      return 0;
+    }
+  bzero((char *) &u, sizeof u);
+#ifdef GETUTENT
+  setutent();
+  strncpy(u.ut_line, slot, sizeof(u.ut_line));
+  if ((uu = getutline(&u)) == 0)
+    {
+      Msg(0, "Utmp slot not found -> not removed");
+      return -1;
+    }
+# ifdef _SEQUENT_
+  if (ut_delete_user(slot, uu->ut_pid, 0, 0) == 0)
+# else
+  uu->ut_type = DEAD_PROCESS;
+  uu->ut_exit.e_termination = 0;
+  uu->ut_exit.e_exit= 0;
+  if (pututline(uu) == 0)
+# endif
+#else  /* GETUTENT */
+  (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
+# ifdef apollo
+  if (read(utmpf, (char *) up, sizeof u) != sizeof u)
+    {
+      DeadlyMsg = 0;
+      Msg(errno, "cannot read %s?", UTMPFILE);
+      sleep(1);
+    }
+  (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
+  bzero(up->ut_name, sizeof(u.ut_name));
+  bzero(up->ut_host, sizeof(u.ut_host));
+  if (write(utmpf, (char *)up, sizeof u) != sizeof u)
+# else
+  if (write(utmpf, (char *) &u, sizeof u) != sizeof u)
+# endif /* apollo */
+#endif
+    {
+#ifdef NETHACK
+      if (nethackflag)
+        Msg(errno, "%s is too hard to dig in.", UTMPFILE);
+      else
+#endif
+      Msg(errno,"Could not write %s.", UTMPFILE);
+#ifdef apollo
+      close(utmpf);
+      free(up);
+#endif
+      return -1;
+    }
+  debug("RemoveUtmp successfull\n");
+  wi->slot = (slot_t) -1;
+#ifdef apollo
+  close(utmpf);
+  free(up);
+#endif
+  return 0;
+}
+
+#endif /* UTMPOK */
+
+#if !defined(GETTTYENT) && !defined(GETUTENT)
+
+static void setttyent()
+{
+  struct stat s;
+  register int f;
+  register char *p, *ep;
+
+  if (ttnext)
+    {
+      ttnext = tt;
+      return;
+    }
+  if ((f = open(ttys, O_RDONLY)) == -1 || fstat(f, &s) == -1)
+    Msg(errno, ttys);
+  if ((tt = malloc((unsigned) s.st_size + 1)) == 0)
+    Msg_nomem;
+  if (read(f, tt, s.st_size) != s.st_size)
+    Msg(errno, ttys);
+  close(f);
+  for (p = tt, ep = p + s.st_size; p < ep; ++p)
+    if (*p == '\n')
+      *p = '\0';
+  *p = '\0';
+  ttnext = tt;
+}
+
+static struct ttyent *getttyent()
+{
+  static struct ttyent t;
+
+  if (*ttnext == '\0')
+    return NULL;
+  t.ty_name = ttnext + 2;
+  ttnext += strlen(ttnext) + 1;
+  return &t;
+}
+
+#endif /* GETTTYENT */
+
+#ifdef LOADAV
+# ifdef LOADAV_NEXT
+void
+InitNeXTLoadAvg()
+{
+  error = processor_set_default(host_self(), &default_set);
+  if (error != KERN_SUCCESS)
+    mach_error("Error calling processor_set_default", error);
+  else
+    avenrun = 1;
+}
+
+int
+GetAvenrun()
+{
+  info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
+  error = processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, &host,
+                            (processor_set_info_t)&info, &info_count);
+  if (error != KERN_SUCCESS)
+    {
+      mach_error("Error calling processor_set_info", error);
+      return 0;
+    }
+  else
+    {
+      loadav = (float)info.load_average / LOAD_SCALE;
+      return 1;
+    }
+}
+
+# else /* need kmem for load avg */
+
+void
+InitKmem()
+{
+  debug("Init Kmem...\n");
+#  ifndef apollo
+  if ((kmemf = open(KmemName, O_RDONLY)) == -1)
+    return;
+  debug("Kmem opened\n");
+  nl[0].n_name = AvenrunSym;
+  debug2("Searching in %s for %s\n", UnixName, nl[0].n_name);
+  nlist(UnixName, nl);
+  if (/* nl[0].n_type == 0 || */ nl[0].n_value == 0)
+    {
+      close(kmemf);
+      return;
+    }
+#   ifdef sgi
+  nl[0].n_value &= ~(1 << 31); /* clear upper bit */
+#   endif /* sgi */
+  debug("AvenrunSym found!!\n");
+#  endif /* apollo */
+  avenrun = 1;
+}
+
+int
+GetAvenrun()
+{
+# ifdef apollo
+  int load[3];
+  register int i;
+
+  proc1_$get_loadav(load);
+  for (i = 0; i < 3; i++)
+    loadav[i] = (double)load[i] / 65536.0;
+# else
+  if (lseek(kmemf, (off_t) nl[0].n_value, 0) == (off_t) - 1)
+    return 0;
+  if (read(kmemf, (char *) loadav, sizeof loadav) != sizeof loadav)
+    return 0;
+# endif /* apollo */
+
+  return 1;
+}
+
+# endif /* !NeXT, need kmem for load avg */
+#endif /* LOADAV */
+
+/*
+ * (Almost) secure open and fopen... mlschroe.
+ */
+
+FILE *
+secfopen(name, mode)
+char *name;
+char *mode;
+{
+  FILE *fi;
+#ifdef NOREUID
+  int flags, fd;
+#endif
+
+  debug2("secfopen(%s, %s)\n", name, mode);
+  if (eff_uid == real_uid)
+    return(fopen(name, mode));
+#ifndef NOREUID
+  setreuid(eff_uid, real_uid);
+  setregid(eff_gid, real_gid);
+  fi = fopen(name, mode);
+  setreuid(real_uid, eff_uid);
+  setregid(real_gid, eff_gid);
+#else
+  if (mode[0] && mode[1] == '+')
+    flags = O_RDWR;
+  else
+    flags = (mode[0] == 'r') ? O_RDONLY : O_WRONLY;
+  if (mode[0] == 'w')
+    flags |= O_CREAT | O_TRUNC;
+  else if (mode[0] == 'a')
+    flags |= O_CREAT | O_APPEND;
+  else if (mode[0] != 'r')
+    {
+      errno = EINVAL;
+      return(0);
+    }
+  if ((fd = secopen(name, flags, 0666)) < 0)
+    return(0);
+  if ((fi = fdopen(fd, mode)) == 0)
+    {
+      close(fd);
+      return(0);
+    }
+#endif
+  return(fi);
+}
+
+
+int
+secopen(name, flags, mode)
+char *name;
+int flags;
+int mode;
+{
+  int fd;
+#ifdef NOREUID
+  int q;
+  struct stat stb;
+#endif
+
+  debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode);
+  if (eff_uid == real_uid)
+    return(open(name, flags, mode));
+#ifndef NOREUID
+  setreuid(eff_uid, real_uid);
+  setregid(eff_gid, real_gid);
+  fd = open(name, flags, mode);
+  setreuid(real_uid, eff_uid);
+  setregid(real_gid, eff_gid);
+#else
+  /* Truncation/creation is done in UserContext */
+  if ((flags & O_TRUNC) || ((flags & O_CREAT) && access(name, F_OK)))
+    {
+      if (UserContext() > 0)
+       {
+          if ((fd = open(name, flags, mode)) >= 0)
+           {
+             close(fd);
+             UserReturn(0);
+            }
+         if (errno == 0)
+           errno = EACCES;
+         UserReturn(errno);
+       }
+      if (q = UserStatus())
+       {
+         if (q > 0)
+           errno = q;
+          return(-1);
+       }
+    }
+  if (access(name, F_OK))
+    return(-1);
+  if ((fd = open(name, flags & ~(O_TRUNC | O_CREAT), 0)) < 0)
+    return(-1);
+  debug("open successful\n");
+  if (fstat(fd, &stb))
+    {
+      close(fd);
+      return(-1);
+    }
+  debug("fstat successful\n");
+  if (stb.st_uid != real_uid)
+    {
+      switch (flags & (O_RDONLY | O_WRONLY | O_RDWR))
+        {
+       case O_RDONLY:
+         q = 0004;
+         break;
+       case O_WRONLY:
+         q = 0002;
+         break;
+       default:
+         q = 0006;
+         break;
+        }
+      if ((stb.st_mode & q) != q)
+       {
+          debug("secopen: permission denied\n");
+         close(fd);
+         errno = EACCES;
+         return(-1);
+       }
+    }
+#endif
+  debug1("secopen ok - returning %d\n", fd);
+  return(fd);
+}
+
+#ifdef BUGGYGETLOGIN
+char *
+getlogin()
+{
+  char *tty;
+#ifdef utmp
+# undef utmp
+#endif
+  struct utmp u;
+  static char retbuf[sizeof(u.ut_user)+1];
+  int fd;
+
+  for (fd = 0; fd <= 2 && (tty = ttyname(fd)) == NULL; fd++)
+    ;
+  if ((tty == NULL) || ((fd = open(UTMP_FILE, O_RDONLY)) < 0))
+    return NULL;
+  tty = stripdev(tty);
+  retbuf[0] = '\0';
+  while (read(fd, &u, sizeof(struct utmp)) == sizeof(struct utmp))
+    {
+      if (!strncmp(tty, u.ut_line, sizeof(u.ut_line)))
+       {
+         strncpy(retbuf, u.ut_user, sizeof(u.ut_user));
+         retbuf[sizeof(u.ut_user)] = '\0';
+         if (u.ut_type == USER_PROCESS)
+           break;
+       }
+    }
+  close(fd);
+
+  return *retbuf ? retbuf : NULL;
+}
+#endif
diff --git a/usr/othersrc/public/screen-3.2/screen3.2/patchlevel.h b/usr/othersrc/public/screen-3.2/screen3.2/patchlevel.h
new file mode 100644 (file)
index 0000000..96fd1d1
--- /dev/null
@@ -0,0 +1,75 @@
+/* Copyright (c) 1991
+ *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Noteworthy contributors to screen's design and implementation:
+ *     Wayne Davison (davison@borland.com)
+ *     Patrick Wolfe (pat@kai.com, kailand!pat)
+ *     Bart Schaefer (schaefer@cse.ogi.edu)
+ *     Nathan Glasser (nathan@brokaw.lcs.mit.edu)
+ *     Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
+ *     Howard Chu (hyc@hanauma.jpl.nasa.gov)
+ *     Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
+ *     Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
+ *     Marc Boucher (marc@CAM.ORG)
+ *
+ ****************************************************************
+ */
+
+/****************************************************************
+ * $Header: /src.stand/pub/utilities/screen/3.2/RCS/patchlevel.h,v 1.2 92/02/03 02:27:59 jnweiger Exp $ 
+ *
+ * patchlevel.h: Our life story.
+ *   8.7.91 -- 3.00.01 -wipe and a 'setenv TERM dumb' bugfix.
+ *  17.7.91 -- 3.00.02 another patchlevel by Wayne Davison
+ *  31.7.91 -- 3.00.03 E0, S0, C0 for flexible semi-graphics, nonblocking 
+ *                     window title input and 'C-a :' command input.
+ *  10.8.91 -- 3.00.04 scrollback, markkeys and some bugfixes.
+ *  13.8.91 -- 3.00.05 mark routine improved, ansi prototypes added.
+ *  20.8.91 -- 3.00.06 screen -h, faster GotoPos in overlay, termcap %.
+ *                     instead of %c
+ *  28.8.91 -- 3.00.07 environment variable support. security. terminfo.
+ *                     pyramid and ultrix support.
+ *  07.9.91 -- 3.00.99 secopen(), MIPS support, SVR4 support.
+ *  09.9.91 -- 3.01.00 backspace bug fixed.
+ * 03.10.91 -- 3.01.01 ansi.c: null-ptr fixed, CLS now saves to scrollback.
+ *                     Using setresuid on hpux. Memory leak fixed.
+ *                    Better GotoPos(). Support for IC. Another resize bug.
+ *                     Detach() w/o fore crashed. -T and -A(dapt) option.
+ *                     GNU copyleft.
+ * 19.12.91 -- 3.01.02 flow now really automatic (autoflow killed).
+ *                    7 bit restriction removed from WriteString().
+ * 09.01.92 -- 3.01.03 flow reattach bug fixed. VDISCARD bug fixed.
+ * 13.01.92 -- 3.01.04 new flow concept: ^Af toggles now three states
+ * 21.01.92 -- 3.01.05 '^A:screen 11' bug fixed. aflag in DoScreen().
+ *                     Some code cleanup. attach_tty and display_tty[]
+ *                     added.
+ * 26.01.92 -- 3.01.06 apollo support, "hardcopy_append on", "bufferfile", 
+ *                     SECURITY PROBLEM cleared..
+ * 28.01.92 -- 3.01.07 screen after su allowed. Pid became part of 
+ *                     SockName. sysvish 14 character restriction considered.
+ * 31.01.92 -- 3.02.00 Ultrix port, Irix 3.3 SGI port, shadow pw support,
+ *                     data loss on stdin overflow fixed. "refresh off".
+ */
+
+#define ORIGIN "FAU"
+#define REV 3
+#define VERS 2
+#define PATCHLEVEL 0
+#define DATE "01/31/92"
+#define STATE ""
diff --git a/usr/othersrc/public/screen-3.2/screen3.2/putenv.c b/usr/othersrc/public/screen-3.2/screen3.2/putenv.c
new file mode 100644 (file)
index 0000000..d150225
--- /dev/null
@@ -0,0 +1,202 @@
+/* Copyright (c) 1991
+ *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Noteworthy contributors to screen's design and implementation:
+ *     Wayne Davison (davison@borland.com)
+ *     Patrick Wolfe (pat@kai.com, kailand!pat)
+ *     Bart Schaefer (schaefer@cse.ogi.edu)
+ *     Nathan Glasser (nathan@brokaw.lcs.mit.edu)
+ *     Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
+ *     Howard Chu (hyc@hanauma.jpl.nasa.gov)
+ *     Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
+ *     Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
+ *     Marc Boucher (marc@CAM.ORG)
+ *
+ ****************************************************************
+ */
+
+/*
+ *  putenv  --  put value into environment
+ *
+ *  Usage:  i = putenv (string)
+ *    int i;
+ *    char  *string;
+ *
+ *  where string is of the form <name>=<value>.
+ *  If "value" is 0, then "name" will be deleted from the environment.
+ *  Putenv returns 0 normally, -1 on error (not enough core for malloc).
+ *
+ *  Putenv may need to add a new name into the environment, or to
+ *  associate a value longer than the current value with a particular
+ *  name.  So, to make life simpler, putenv() copies your entire
+ *  environment into the heap (i.e. malloc()) from the stack
+ *  (i.e. where it resides when your process is initiated) the first
+ *  time you call it.
+ *
+ *  HISTORY
+ *  3-Sep-91 Michael Schroeder (mlschroe). Modified to behave as
+ *    as putenv.
+ * 16-Aug-91 Tim MacKenzie (tym) at Monash University. Modified for
+ *    use in screen (iScreen) (ignores final int parameter)
+ * 14-Oct-85 Michael Mauldin (mlm) at Carnegie-Mellon University
+ *      Ripped out of CMU lib for Rob-O-Matic portability
+ * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
+ *    Created for VAX.  Too bad Bell Labs didn't provide this.  It's
+ *    unfortunate that you have to copy the whole environment onto the
+ *    heap, but the bookkeeping-and-not-so-much-copying approach turns
+ *    out to be much hairier.  So, I decided to do the simple thing,
+ *    copying the entire environment onto the heap the first time you
+ *    call putenv(), then doing realloc() uniformly later on.
+ */
+#include "config.h"
+
+#if defined(NEEDSETENV)
+
+#define EXTRASIZE 5        /* increment to add to env. size */
+
+char *index(), *malloc(), *realloc();
+int   strlen();
+
+static int  envsize = -1;    /* current size of environment */
+extern char **environ;        /* the global which is your env. */
+
+static int  findenv();        /* look for a name in the env. */
+static int  newenv();        /* copy env. from stack to heap */
+static int  moreenv();        /* incr. size of env. */
+
+int unsetenv(name)
+char *name;
+{
+  register int i;
+  
+  i = findenv(name);
+  if (i<0)
+    return;                    /* Already here */
+  
+  free(environ[i]);
+  if (envsize > 0)
+    envsize--;
+  for (; environ[i]; i++)
+    environ[i] = environ[i+1];
+}
+
+int putenv(string)
+char *string;
+{ 
+  register int  i, j;
+  register char *p;
+  
+  if (envsize < 0)
+    {                          /* first time putenv called */
+      if (newenv() < 0)                /* copy env. to heap */
+       return (-1);
+    }
+  
+  i = findenv(string);         /* look for name in environment */
+
+  if (i < 0)
+    {                  /* name must be added */
+      for (i = 0; environ[i]; i++);
+      if (i >= (envsize - 1))
+       {                       /* need new slot */
+         if (moreenv() < 0)
+           return (-1);
+       }
+      p = malloc(strlen(string) + 1);
+      if (p == 0)              /* not enough core */
+       return (-1);
+      environ[i + 1] = 0;      /* new end of env. */
+    }
+  else
+    {                  /* name already in env. */
+      p = realloc(environ[i], strlen(string) + 1);
+      if (p == 0)
+       return (-1);
+    }
+  sprintf(p, "%s", string); /* copy into env. */
+  environ[i] = p;
+  
+  return (0);
+}
+
+static int  findenv(name)
+char *name;
+{
+  register char *namechar, *envchar;
+  register int  i, found;
+  
+  found = 0;
+  for (i = 0; environ[i] && !found; i++)
+    { 
+      envchar = environ[i];
+      namechar = name;
+      while (*namechar && *namechar != '=' && (*namechar == *envchar))
+        { 
+         namechar++;
+         envchar++;
+        }
+      found = ((*namechar == '\0' || *namechar == '=') && *envchar == '=');
+    }
+  return (found ? i - 1 : -1);
+}
+
+static int newenv()
+{ 
+  register char **env, *elem;
+  register int i, esize;
+
+  for (i = 0; environ[i]; i++)
+    ;
+  esize = i + EXTRASIZE + 1;
+  env = (char **)malloc(esize * sizeof (elem));
+  if (env == 0)
+    return (-1);
+
+  for (i = 0; environ[i]; i++)
+    { 
+      elem = malloc(strlen(environ[i]) + 1);
+      if (elem == 0)
+       return (-1);
+      env[i] = elem;
+      strcpy(elem, environ[i]);
+    }
+   
+  env[i] = 0;
+  environ = env;
+  envsize = esize;
+  return (0);
+}
+
+static int moreenv()
+{ 
+  register int  esize;
+  register char **env;
+  
+  esize = envsize + EXTRASIZE;
+  env = (char **)realloc(environ, esize * sizeof (*env));
+  if (env == 0)
+    return (-1);
+  environ = env;
+  envsize = esize;
+  return (0);
+}
+
+#endif /* NEEDSETENV */
+
+
diff --git a/usr/othersrc/public/screen-3.2/screen3.2/screen.1 b/usr/othersrc/public/screen-3.2/screen3.2/screen.1
new file mode 100644 (file)
index 0000000..41c5bf7
--- /dev/null
@@ -0,0 +1,1764 @@
+.if n .ds Q \&"
+.if n .ds U \&"
+.if t .ds Q ``
+.if t .ds U ''
+.TH SCREEN 1 "31 January 1992"
+.UC 4
+.SH NAME
+screen \- screen manager with VT100/ANSI terminal emulation
+.SH SYNOPSIS
+.B screen
+[
+.B -\fIoptions\fP
+] [
+.B \fIcmd\fP
+[
+.B \fIargs\fP
+] ]
+.br
+.B screen \-r
+[
+.BR \fI\fP[\fIpid.\fP]\fItty\fP[\fI.host\fP]
+]
+.ta .5i 1.8i
+.SH DESCRIPTION
+.I Screen
+is a full-screen window manager that
+multiplexes a physical terminal between several processes (typically
+interactive shells).
+Each virtual terminal provides the functions
+of the DEC VT100 terminal and, in addition, several control functions
+from the ANSI X3.64 (ISO 6429) and ISO 2022 standards
+(e.\|g. insert/delete line and support for multiple character sets).
+There is a scrollback history buffer for each virtual terminal and a 
+copy-and-paste mechanism that allows moving text regions between
+windows.
+.PP 
+The name of this program was changed to
+.I iScreen
+to be able to distinguish it from Oliver Laumann's original 
+.I screen
+program. Despite that fact, this manual will continue to use the name
+.IR screen .
+This is, because often the binary is installed as 'screen'.
+.PP
+When
+.I screen
+is called, it creates a single window with a shell in it (or the specified
+command) and then gets out of your way so that you can use the program as you
+normally would.
+Then, at any time, you can create new (full-screen) windows with other programs
+in them (including more shells), kill existing windows, view a list of the
+current windows, turn output logging on and off, copy-and-paste text between
+windows, view the scrollback history, switch between windows
+in whatever manner you wish, etc.
+When a program terminates,
+.I screen
+kills the window that contained it.
+If this window was in the foreground, the display switches to the previous
+window; if none are left,
+.I screen
+exits.
+.PP
+Everything you type is sent to the program running in the current window.
+The only exception to this is the one keystroke that is used to initiate
+a command to the window manager.
+By default, each command begins with a control-a (abbreviated C-a from
+now on), and is followed by one other keystroke.
+The command character and all the key bindings can be fully customized
+to be anything you like, though they are always two characters in length.
+.PP
+The standard way to create a new window is to type \*QC-a c\*U.
+This creates a new window running a shell and switches to that
+window immediately, regardless of the state of the process running
+in the current window.
+Similarly, you can create a new window with a custom command in it by
+first binding the command to a keystroke (in your .screenrc file) and
+then using it just like the \*QC-a c\*U command.
+In addition, new windows can be created by running a command like:
+.IP
+screen emacs prog.c
+.PP
+from a shell prompt within a previously created window.
+This will not run another copy of 
+.IR screen ,
+but will instead supply the
+command name and its arguments to the window manager who will use it to
+create the new window.
+The above example would start the emacs editor (editing prog.c) and switch
+to its window.
+.PP
+If \*Q/etc/utmp\*U is writable by
+.IR screen ,
+an appropriate record will be written to this file for each window, and
+removed when the window is terminated.
+This is useful for working with \*Qtalk\*U, \*Qscript\*U, \*Qshutdown\*U,
+\*Qrsend\*U, \*Qsccs\*U and other similar programs that use the utmp
+file to determine who you are. As long as 
+.I screen
+is active on your terminal,
+the terminals own record is removed from the utmp file. See also \*QC-a L\*U.
+.SH GETTING STARTED
+Before you begin to use
+.I screen
+you'll need to make sure you have correctly selected your terminal type,
+just as you would for any other termcap/terminfo program.
+(You can do this by using
+.IR tset
+or
+.IR stty , 
+for example.)
+.PP
+If you're impatient and want to get started without doing a lot more reading,
+you should remember this one command:  \*QC-a ?\*U.
+Typing these two characters will display a list of the available
+.I screen
+commands and their bindings. Each keystroke is discussed in
+the section \*QCOMMAND KEYS\*U. The manual section \*QCUSTOMIZATION\*U 
+deals with the contents of your .screenrc.
+.PP
+If possible, choose a version of your terminal's termcap that has automatic
+margins turned \fIoff\fP.
+This will ensure an accurate and optimal update of the screen
+in all circumstances.
+The next best thing is an auto-margin terminal that allows the last position
+on the screen to be updated without scrolling the screen (such as a vt100).
+This also allows the entire screen to be updated.
+Lastly, if all you've got is a \*Qtrue\*U auto-margin terminal
+.I screen
+will be content to use it, but updating a character put into the last position
+on the screen may not be possible until the screen scrolls or the character
+is moved into a safe position in some other way.
+This delay can be shortened by using a terminal with insert-character
+capability.
+.PP
+If your terminal is of the second type (firm-margined `am'), you will
+want to let
+.I screen
+know about this, since a normal termcap doesn't distinguish this type of
+automatic margins from a \*Qtrue\*U `am' terminal.
+You do this by specifying the `LP' capability in your termcap
+(see the \*Qtermcap\*U .screenrc command), or by using the
+.B \-L
+command-line option.
+.I Screen
+needs this information to correctly update the screen.
+.PP
+If you are using a \*Qtrue\*U auto-margin terminal (no `LP') at low baud
+rates, you may want to turn on a more optimal output mode by including the
+flag `OP' in your termcap entry, or by specifying the
+.B \-O
+command-line option.
+The trade-off is that
+.I screen
+will no-longer accurately emulate the vt100's line-end quirks (e.\|g. the
+screen will scroll after putting \fIone\fP character in the last screen
+position).
+.SH "COMMAND KEYS"
+As mentioned, each
+.I screen
+command consists of a
+\*QC-a\*U followed by one other character.
+For your convenience, all commands that are bound to lower-case letters are
+also bound to their control character counterparts (with the exception
+of \*QC-a a\*U; see below), thus, \*QC-a c\*U as well as \*QC-a C-c\*U can
+be used to create a window.
+.PP
+The following keystroke commands are available:
+.IP "\fBC-a 0\fP  -  \fBC-a 9\fP   (select0 - select9)"
+Switch to the window with the number 0 through 9.
+When a new window is established, the first available number from the
+range 0..9 is assigned to this window.
+Thus, the first window can be activated by \*QC-a 0\*U (there can be no more
+than 10 windows present at any one time).
+.IP "\fBC-a C-a\fP   (other)"
+Switch to the window displayed previously.
+Note that this function defaults to the command character typed twice,
+unless overridden; for instance, if you use the option \*Q\fB\-e]x\fP\*U,
+this function becomes \*Q]]\*U, not \*Q]C-a\*U.
+.IP "\fBC-a a\fP\0\0\0\0\0"
+Send the command character (C-a) to the processes in the current window.
+.IP "\fBC-a A\fP   (aka)"
+Allow the user to enter an a.\|k.\|a (also-known-as). for the current window.
+.IP "\fBC-a c\fP  or  \fBC-a C-c\fP   (shell)"
+Create a new window with a shell and switch to that window.
+.IP "\fBC-a C\fP   (clear)"
+Clear the screen.
+.IP "\fBC-a d\fP  or  \fBC-a C-d\fP   (detach)"
+Detach
+.I screen
+(disconnect it from the terminal and put it into the background).
+A detached
+.I screen
+can be resumed by invoking
+.I screen
+with the
+.B \-r
+option. (See also section \*QCOMMAND-LINE OPTIONS\*U.)
+.IP "\fBC-a D D\fP   (pow_detach)"
+Power detach. Mainly the same as above, but also sends a HANGUP signal to
+the parent process of
+.IR screen .
+CAUTION: This will result in a logout, when 
+.I screen
+was started from your login shell.
+.IP "\fBC-a f\fP  or  \fBC-a C-f\fP   (flow)"
+Cycles the current window's flow-control setting from "automatic" to "on" to 
+"off", see the section titled FLOW-CONTROL for details.
+.IP "\fBC-a C-g\fP   (vbell)"
+Toggles 
+.I screen's
+visual bell mode. If your terminal does not support
+a visual bell, a `vbell-message' is displayed in the status line. 
+.IP "\fBC-a h\fP  or  \fBC-a C-h\fP   (hardcopy)"
+Write a hardcopy of the current window to the file \*Qhardcopy.\fIn\fP\*U
+in the window's default directory, where \fIn\fP is the number
+of the current window. 
+.IP "\fBC-a H\fP   (log)"
+Begins/ends logging of the current window to the file \*Qscreenlog.\fIn\fP\*U
+in the window's default directory, where \fIn\fP is the number
+of the current window.
+The session log is appended to the previous contents of the file
+if it already exists. 
+The current contents and the contents of the scrollback history are not
+included in the session log.
+.IP "\fBC-a i\fP  or  \fBC-a C-i\fP   (info)"
+Uses the message line to display some information about the current window:
+the cursor position in the form \*Q(column,row)\*U starting with \*Q(1,1)\*U,
+the terminal width and height plus the size of the scrollback buffer in lines, 
+like in \*U(80,24)+50\*U, various flag settings (flow-control, insert mode,
+origin
+mode, wrap mode, application-keypad mode, output logging, and activity
+monitoring (`+' indicates enabled, `-' not)),
+the currently active character set (\fIG0\fP, \fIG1\fP, \fIG2\fP,
+or \fIG3\fP), and in square brackets the terminal character sets that are
+currently designated as \fIG0\fP through \fIG3\fP.
+For system information use \*QC-a t\*U.
+.IP "\fBC-a k\fP  or  \fBC-a C-k\fP   (kill)"
+Kill the current window and switch to the previously displayed window.
+Note:
+.I Emacs
+users should keep this command in mind, when killing a line.
+It is recommended not to use \*QC-a\*U as the
+.I screen
+escape key or that kill is rebound to \*QC-a K\*U.
+.IP "\fBC-a l\fP  or  \fBC-a C-l\fP   (redisplay)"
+Redisplay the current window.
+.IP "\fBC-a L\fP   (login)"
+Adds or removes the entry in /etc/utmp file for the current window.
+This controls if the window is `logged in'. See also above.
+Additionally to that toggle, it is convenient having a `log in' and a `log out'
+key. E.\|g. `bind I set login on' and `bind O set login off' will map these
+keys to be C-a I and C-a O.
+.IP "\fBC-a m\fP  or  \fBC-a C-m\fP   (lastmsg)"
+Repeat the last message displayed in the message line.
+Useful if you're typing when a message appears, because (unless your terminal
+has a status line) the message goes away when you press a key.
+.IP "\fBC-a M\fP   (monitor)"
+Toggles monitoring of the current window.
+When monitoring is turned on and the affected window is switched into the
+background, you will receive the activity notification message in the
+status line at the first sign of output and the window will also be marked
+with an `@' in the window-status display.
+Monitoring is initially off for all windows.
+.IP "\fBC-a space\fP  or  \fBC-a n\fP  or  \fBC-a C-n\fP   (next)"
+Switch to the next window.
+This function can be used repeatedly to cycle through the list of windows.
+(Some terminals require you to release the control key before pressing space.)
+.IP "\fBC-a p\fP  or  \fBC-a C-p\fP   (prev)"
+Switch to the previous window (the opposite of \fBC-a n\fP).
+.IP "\fBC-a q\fP  or  \fBC-a C-q\fP   (xon)"
+Send a control-q to the program in the current window.
+.IP "\fBC-a r\fP  or  \fBC-a C-r\fP   (wrap)"
+Toggle the current window's line-wrap setting (turn the current window's
+automatic margins on and off).
+.IP "\fBC-a s\fP  or  \fBC-a C-s\fP   (xoff)"
+Send a control-s to the program in the current window.
+.IP "\fBC-a t\fP  or  \fBC-a C-t\fP   (time)"
+Uses the message line to display the time of day, the host name, and the load
+averages over 1, 5, and 15 minutes (if this is available on your system).
+For window specific information use \*QC-a i\*U.
+.IP "\fBC-a v\fP  or  \fBC-a C-v\fP   (version)"
+Display the version and compilation date.
+.IP "\fBC-a w\fP  or  \fBC-a C-w\fP   (windows)"
+Uses the message line to display a list of all the windows.
+Each window is listed by number with the name of process that has been
+started in the window (or its a.\|k.\|a.);
+the current window is marked with a `*';
+the previous window is marked with a `-';
+all the windows that are \*Qlogged in\*U are marked with a `$';
+a background window that has received a bell is marked with a `!';
+a background window that is being monitored and has had activity occur
+is marked with an `@';
+a window which has output logging turned on is marked with `(L)'.
+.IP "\fBC-a W\fP   (width)"
+Toggle the window width between 80 and 132 columns. As this command became
+a toggle, \*QC-a N\*U is no longer supported.
+This requires a capable terminal and the termcap entries \*QZ0\*U and \*QZ1\*U.
+See the \*Qtermcap\*U command in section \*QCUSTOMIZATION\*U 
+for more information.
+.IP "\fBC-a x\fP  or  \fBC-a C-x\fP   (lock)"
+Call a screenlock program (/local/bin/lck or /usr/bin/lock or a builtin, if no
+other is available). Screen does not accept any command keys until this program
+terminates. Meanwhile processes in the windows may continue, as the windows 
+are in the `detached' state. The screenlock program may be changed through the
+environment variable $LOCKPRG (which must be set in the shell from which 
+.I screen
+is started) and is executed with the user's uid and gid.
+.IP "\fBC-a z\fP  or  \fBC-a C-z\fP   (suspend)"
+Suspend
+.IR screen .
+The windows are in the `detached' state, while 
+.IR screen
+is suspended.
+.IP "\fBC-a Z\fP   (reset)"
+Reset the virtual terminal to its \*Qpower-on\*U values.
+.IP "\fBC-a .\fP   (termcap)"
+Write the termcap entry for the virtual terminal of the currently active
+window to the file \*Q.termcap\*U in the user's \*Q$HOME/.screen\*U directory
+(or wherever 
+.I screen
+stores its sockets. See the \*QFILES\*U section below).
+This termcap entry is identical to the value of the environment variable
+$TERMCAP that is set up by
+.I screen
+for each window. For terminfo based systems you will need to run a converter
+like 
+.IR captoinfo
+and then compile the entry with 
+.IR tic .
+.IP "\fBC-a ?\fP   (help)"
+Displays a help screen showing you all the key bindings.
+The first pages list all the internal commands followed by their bindings.
+Subsequent pages will display the custom commands, one command per key.
+Press space when you're done reading each page, or return to exit early.
+All other characters are ignored, except for the command character, which will
+exit the help display and begin a command.
+.IP "\fBC-a C-\e\fP   (quit)"
+Kill all windows and terminate
+.IR screen .
+Note that on vt100-style terminals the keys C-4 and C-\e are identical.
+So be careful not to write C-a C-4 when selecting window no. 4.
+Use the empty bind command (as in \*Qbind '^\'\*U) to remove a key binding.
+.IP "\fBC-a :\fP   (colon)"
+Allows you to enter \*Q.screenrc\*U command lines as well as names of 
+key-bound-functions. Useful for on-the-fly modification of key bindings, 
+specific window creation and changing settings. Settings of the current window
+can be changed by prepending the command (if appropriate) with the keyword
+\*Qset\*U.  If you consider this as the `Ex command mode' of 
+.IR screen ,
+you may regard \*QC-a esc\*U as its `Vi command mode'.
+.IP "\fBC-a [\fP  or  \fBC-a C-[\fP  or  \fBC-a esc\fP   (copy)"
+Enter copy/scrollback mode. This allows you to copy text from the current
+window and its history into the paste buffer. In this mode a vi-like
+`full screen editor' is active:
+.br
+.IR "Movement keys" :
+.br
+\fBh\fP, \fBj\fP, \fBk\fP, \fBl\fP move the cursor line by line or column by column.
+.br
+\fB0\fP, \fB^\fP and \fB$\fP move to the leftmost column, to the first or last
+non-whitespace
+character on the line.
+.br
+\fBH\fP, \fBM\fP and \fBL\fP move the cursor to the leftmost column
+of the top, center or bottom line of the window. 
+.br
+\fB+\fP and \fB-\fP positions one line up and down.
+.br
+\fBG\fP moves to the specified absolute line (default: end of buffer).
+.br 
+\fB|\fP moves to the specified absolute column.
+.br
+\fBw\fP, \fBb\fP, \fBe\fP move the cursor word by word.
+.br 
+\fBC-u\fP and \fBC-d\fP scroll the display up/down by the specified amount of 
+lines while preserving the cursor position. (Default: half screenfull). 
+.br
+\fBC-b\fP and \fBC-f\fP scroll the display up/down a full screen.
+.br
+\fBg\fP moves to the beginning of the buffer, whereas
+.br
+\fB%\fP jumps to the specified percentage.
+.br
+.IR Note :
+Emacs style movement keys can be customized by a .screenrc command. (E.\|g.
+markkeys "h=^B:l=^F:$=^E") There is no simple method for a full emacs-style
+keymap, as this involves multi-character codes.
+.br
+.IR Marking :
+.br
+The copy range is specified by setting two marks. The text between these marks 
+will be highlighted. Press \fBspace\fP to set the first or second mark
+respectively.
+.br
+\fBY\fP and \fBy\fP can be used to mark one whole line or to mark from 
+start of line.
+.br
+\fBW\fP marks exactly one word. 
+.br 
+.IR "Repeat count" :
+.br
+Any of these commands can be prefixed with a number (by pressing digits 
+\fB0\fP..\fB9\fP) which
+is taken as a repeat count. Example: \*QC-a C-[ H 10 j 5 Y\*U will copy lines
+11 to 15 into the pastebuffer.
+.br
+.IR Specials :
+.br
+There are however some keys that act differently here and in
+.IR vi .
+.I Vi
+does not allow to yank rectangular blocks of text, but
+.I screen
+does. Press 
+.br
+\fBc\fP or \fBC\fP to set the left or right margin respectively. If no repeat count is
+given, both default to the current cursor position. Try this on a rather 
+full text screen as an example: \*QC-A [ S-M 20 l SPACE c 10 l 5 j S-C SPACE\*U.
+.br
+\fBJ\fP joins lines. It toggles between 
+3 modes: lines separated by a newline character (012), lines glued seamless,
+lines separated by a single whitespace. Note that you can prepend the newline
+character with a carriage return character, by issuing a \*Qset crlf on\*U.
+.br
+\fBv\fP is for all the
+.I vi 
+users with \*Q:set numbers\*U - it toggles the left margin between column 9
+and 1.
+.br
+Press \fBa\fP before the final space key to toggle in append mode. Thus
+the contents of the pastebuffer will not be overwritten, but appended to.
+.br
+\fBA\fP toggles in append mode and sets a (second) mark.
+.br
+\fB>\fP sets the (second) mark and writes the contents of the copybuffer to
+the screen-exchange file (/tmp/screen-exchange per default) once copy-mode is 
+finished. This example demonstrates how to dump the whole scrollback buffer 
+to that file: \*QC-A [ g SPACE G $ >\*U.
+.br
+\fB?\fP gives information about the current line and column.
+.IP "\fBC-a ]\fP  or  \fBC-a C-]\fP   (paste)"
+Paste. Write the contents of the paste buffer to the stdin queue of the
+current window.
+.IP "\fBC-a {\fP   (history)"
+Usually users work with a shell that allows easy access to previous commands.
+E.g. csh has the command \*Q!!\*U to repeat the last command executed. 
+.I Screen
+allows you to have a primitive way of re-calling \*Qthe command that
+started ...\*U: You just type the first letter of that command, then hit
+`C-a {' and
+.I screen
+tries to find a previous line that matches with the `prompt character' 
+to the left of the cursor. This line is pasted into this window's input queue.
+Thus you have a crude command history (made up by the visible window and its
+scrollback buffer). 
+.IP "\fBC-a >\fP   (write_buffer)"
+Writes the contents of the paste buffer to a public accessible screen-exchange
+file. This is thought of as a primitive means of communication between
+.I screen
+users on the same host. See also \*QC-a esc\*U.
+.IP "\fBC-a <\fP   (read_buffer)"
+Reads the screen-exchange file into the pastebuffer. See also \*QC-a ]\*U.
+.IP "\fBC-a =\fP   (kill_buffer)"
+Removes the exchange file used by \*QC-a <\*U and \*QC-a >\*U.
+.SH "COMMAND-LINE OPTIONS"
+Screen has the following command-line options:
+.TP 5
+.B \-a
+include \fIall\fP capabilities (with some minor exceptions) in each
+window's termcap, even if
+.I screen
+must redraw parts of the display in order to implement a function.
+.TP 5
+.B "\-c \fIfile\fP"
+override the default configuration file from \*Q$HOME/.screenrc\*U
+to \fIfile\fP.
+.TP 5
+.B "\-d\fP|\fB\-D \fP[\fIpid.tty.host\fP\]\fB"
+does not start
+.IR screen ,
+but detach the elsewhere running 
+.I screen
+session. It has the same effect as typing \*QC-a d\*U from 
+.I screen's
+controlling terminal. \fB-D\fP is the equivalent to the power detach key.
+If no session can be detached, this option is ignored. 
+The combination \*Qscreen -D -r\*U can be used to `transport' the elsewhere 
+running session to this terminal and logout there. 
+Note: It is a good idea to have the status of your sessions checked by means of
+\*Qscreen -list\*U.
+.TP 5
+.B "\-e \fIxy\fP"
+specifies the command character to be \fIx\fP and the character generating a
+literal command character to \fIy\fP (when typed after the command character).
+The default is \*QC-a\*U and `a', which can be specified as \*Q-e^Aa\*U.
+See the \*Qescape\*U .screenrc command for more details.
+.TP 5
+.B "\-f\fP, \fB\-fn\fP, and \fB\-fa"
+turns flow-control on, off, or \*Qautomatic switching mode\*U.
+This can also be defined through the \*Qflow\*U .screenrc command.
+.TP 5
+.B "\-h \fInum\fP"
+Specifies the history scrollback buffer to be \fInum\fP lines high.
+.TP 5
+.B \-i
+will cause the interrupt key (usually C-c) to interrupt the display
+immediately when flow-control is on.
+See the \*Qflow\*U .screenrc command for details.
+.TP 5
+.B "\-l \fPand\fB -ln"
+turns login mode on or off (for /etc/utmp updating).
+This can also be defined through the \*Qlogin\*U .screenrc command.
+.TP 5
+.B "\-ls \fPand\fB -list"
+does not start
+.IR screen ,
+but prints a list of
+.I pid.tty.host
+strings identifying your 
+.I screen
+sessions.
+Sessions marked `detached' can be resumed with \*Qscreen -r\*U. Those marked 
+`attached' are running and have a controlling terminal. Sessions marked as
+`dead' should be thoroughly checked and removed. Ask your system administrator
+if you are not sure. Remove sessions with the \fB-wipe\fP option.
+.TP 5
+.B "\-t \fIname\fP"
+sets the title (a.\|k.\|a.) for the default shell or specified program.
+See also the \*Qshellaka\*U .screenrc command.
+.TP 5
+.B "\-wipe"
+does the same as \*Qscreen -ls\*U, but removes destroyed sessions instead of 
+marking them as `dead'.
+.TP 5
+.B \-L
+tells 
+.I screen
+your auto-margin terminal has a writable last-position on
+the screen.
+This can also be set in your .screenrc by specifying `LP' in a \*Qtermcap\*U
+command.
+.TP 5
+.B \-O
+selects a more optimal output mode for your terminal rather than true vt100
+emulation (only affects auto-margin terminals without `LP').
+This can also be set in your .screenrc by specifying `OP' in a \*Qtermcap\*U
+command.
+.TP 5
+.B "\-r \fP[\fIpid.tty.host\fP]"
+resumes a detached
+.I screen
+session.
+No other options (except \*Q-d -r\*U or \*Q-D -r\*U) may be specified, though
+an optional prefix of [\fIpid.\fP]\fItty.host\fP
+may be needed to distinguish between multiple detached
+.I screen
+sessions.
+.TP 5
+.B \-R
+attempts to resume the first detached 
+.I screen
+session it finds.
+If successful, all other command-line options are ignored.
+If no detached session exists, starts a new session using the specified
+options, just as if
+.B \-R
+were not specified.
+.TP 5
+.B \-s
+sets the default shell to the program specified, instead of the value
+in the environment variable $SHELL (or \*Q/bin/sh\*U if not defined).
+This can also be defined through the \*Qshell\*U .screenrc command.
+.SH CUSTOMIZATION
+The \*Qsocket directory\*U defaults either to $HOME/.screen or preferably
+to /local/screens. If
+.I screen
+is installed setuid-root, then the administrator
+should compile screen with an adequate (not NFS mounted) SOCKDIR. If
+.I screen
+is not running setuid-root, the user can specify any mode 777 directory
+in the environment variable $SCREENDIR.
+.PP
+When
+.I screen
+is invoked, it executes initialization commands from the files
+\*Q/local/etc/screenrc\*U and
+\*Q.screenrc\*U in the user's home directory. These are the \*Qprogrammer's
+defaults\*U that can be overridden in the following ways: For the 
+global screenrc file 
+.I screen
+searches for the environment variable $SYSSCREENRC. The user specific
+screenrc file is searchend in $ISCREENRC, then $SCREENRC, then $HOME/.iscreenrc
+and finally defaults to $HOME/.screenrc. The command line option \fB-c\fP takes
+precedence over the user specific screenrc file.
+Commands in these files are used to set options, bind functions to
+keys, and to automatically establish one or more extra windows at the
+beginning of your
+.I screen
+session.
+Commands are listed one per line, with empty lines being ignored.
+A command's arguments are separated by tabs or spaces, and may be
+surrounded by single or double quotes.
+A `#' turns the rest of the line into a comment, except in quotes.
+Unintelligible lines are warned about and ignored.
+Commands may contain references to environment variables. The 
+syntax is the shell-like "$VAR " or "${VAR}". Note that this causes 
+incompatibilities with previous 
+.I screen
+versions, as now the '$'-sign has to be protected with '\' if no
+variable substitution shall be performed.
+.PP
+Customization can also be done 'on-line'. To enter the command mode type
+`C-a :'. Setting flags (like scrollback, login, etc.) on-line may not have
+the desired effect, as e.\|g. the command "C-a : login on" will affect
+only the settings for the creation of new windows (just like within .screenrc).
+If you intend to change flags
+of the current window, then prepend the command with the keyword "set". E.\|g.
+"C-a : set login on" will log this window in.
+.PP
+The following initialization commands are available:
+.PP
+.ne 3
+.B "activity \fImessage\fP"
+.sp
+When any activity occurs in a background window that is being monitored,
+.I screen
+displays a notification in the message line.
+The notification message can be re-defined by means of the \*Qactivity\*U
+command.
+Each occurrence of `%' in \fImessage\fP is replaced by
+the number of the window in which activity has occurred,
+and each occurrence of `~' is replaced by the definition for bell
+in your termcap (usually an audible bell).
+The default message is
+.sp
+       'Activity in window %'
+.sp
+Note that monitoring is off for all windows by default, but can be altered
+by use of the \*Qmonitor\*U command (C-a M).
+.PP
+.ne 3
+.B "autodetach on\fP|\fBoff"
+.sp
+Sets whether 
+.I screen
+will automatically detach upon hangup, which
+saves all your running programs until they are resumed with a
+.B "screen -r"
+command.
+When turned off, a hangup signal will terminate 
+.I screen
+and all the processes it contains. Autodetach is on by default.
+.PP
+.ne 3
+.B "bell \fImessage\fP"
+.sp
+When a bell character is sent to a background window,
+.I screen
+displays a notification in the message line.
+The notification message can be re-defined by means of the \*Qbell\*U
+command.
+Each occurrence of `%' in \fImessage\fP is replaced by
+the number of the window to which a bell has been sent,
+and each occurrence of `~' is replaced by the definition for bell
+in your termcap (usually an audible bell).
+The default message is
+.sp
+       'Bell in window %'
+.sp
+An empty message can be supplied to the \*Qbell\*U command to suppress
+output of a message line (bell "").
+.PP
+.ne 3
+.B "bind \fP\fIkey\fP [\fIfunction\fP [\fIargs\fP]]"
+.sp
+Bind a function to a key.
+By default, each function provided by
+.I screen
+is bound to one or more keys as indicated by the above table, e.\|g. the
+function to create a new window is bound to \*QC-c\*U and \*Qc\*U.
+The \*Qbind\*U command can be used to redefine the key bindings and to
+define new bindings.
+The \fIkey\fP argument is either a single character, a two-character sequence
+of the form \*Q^x\*U (meaning \*QC-x\*U), a backslash followed by an octal
+number (specifying the ASCII code of the character), or a backslash followed
+by a second character, such as \*Q\e^\*U or \*Q\e\e\*U.
+The argument can also be quoted, if you like.
+If no further argument is given, any previously established binding
+for this key is removed.
+The \fIfunction\fP argument can be one of the following keywords:
+.PP
+.nf
+       select0 Switch to window #0
+       \0\0...
+       select9 Switch to window #9
+       aka     Change the current window's a.\|k.\|a.
+       clear   Clear the screen
+       colon   Enter one \*Q.screenrc\*U command on-the-fly.
+       copy    Select a piece of text.
+       detach  Detach \fIscreen\fP
+       flow    Toggle the current window's flow-control setting
+       hardcopy        Make hardcopy of current window
+       history Use cut&paste to fetch a recently displayed line.
+       help    Display a list of the key bindings in effect
+       info    Display the current window's status information
+       kill    Kill the current window
+       lastmsg Redisplay the last message line
+       lock    Run a screenlock program. 
+       log     Begin/end logging of the current window's output
+       login   Toggle the window's \*Qlogin\*U setting (/etc/utmp entry)
+       monitor Toggle activity monitoring of the current window
+       next    Switch to the next window
+       other   Switch to the window displayed previously
+       paste   Paste in a selected piece of text.
+       pow_detach      Detach \fIscreen\fP and logout.
+       prev    Switch to the previous window
+       quit    Kill all windows and terminate
+       readbuffer      Take text from the exchange file.
+       redisplay       Redisplay current window
+       reset   Reset the window to its \*Qpower-on\*U settings
+       screen  Create a new window with the specified command
+       shell   Create a new window with a shell
+       suspend Suspend \fIscreen\fP
+       termcap Write screen's termcap entry to $HOME/.screencap
+       vbell   Toggle the window's \*Qvbell\*U setting.
+       version Display the version numbers and date last modified
+       width   Toggle the terminal width between 80 and 132 columns
+       windows Display a list of all windows
+       wrap    Toggle the current window's line-wrap setting
+       writebuffer     Store the selected text in the exchange file.
+       xoff    Send a control-s to the current program
+       xon     Send a control-q to the current program
+.fi
+.PP
+Some examples:
+.PP
+.nf
+       bind ' ' windows
+       bind ^f screen telnet foobar
+       bind \e033 screen -ln -t root -h 1000 9 su
+.fi
+.PP
+would bind the space key to the function that displays a list
+of windows (so that the function usually invoked by \*QC-a C-w\*U
+would also be available as \*QC-a space\*U),
+bind \*QC-f\*U to the function \*Qcreate a window with a TELNET
+connection to foobar\*U, and bind \*Qescape\*U to the function
+that creates an non-login window with a.\|k.\|a. \*Qroot\*U in slot #9, with
+a super-user shell and a scrollbackbuffer of 1000 lines.
+.PP
+.ne 3
+.B "bufferfile \fIexchange-file\fP"
+.sp
+Change the filename used for reading and writing with the copybuffer.
+The default is \*Q/tmp/screen-exchange\*U. The following example
+will paste the system's password file into the screen window:
+.PP
+.nf
+       C-a : bufferfile /etc/passwd
+       C-a < C-a ]
+.fi
+.PP
+.ne 3
+.B "chdir \fP[\fIdirectory\fP]"
+.sp
+Change the \fIcurrent directory\fP of
+.I screen
+to the specified directory or, if called without an argument,
+to your home directory (the value of the environment variable $HOME).
+All windows that are created by means of the \*Qscreen\*U command
+from within \*Q.screenrc\*U or by means of \*QC-a : screen ...\*U
+or \*QC-a c\*U use this as their default directory.
+Without a chdir command, this would be the directory from which
+.I screen
+was invoked.
+Hardcopy and log files are always written to the \fIwindow's\fP default
+directory, \fInot\fP the current directory of the process running in the
+window.
+You can use this command multiple times in your .screenrc to start various
+windows in different default directories, but the last chdir value will
+affect all the windows you create interactively.
+.PP
+.ne 3
+.B "crlf on\fP|\fBoff"
+.sp
+This affects the copying of text regions with the `C-a [' command. If it is set
+to `on', lines will be separated by the two character sequence `CR' - `LF'. 
+Otherwise only `LF' is used.
+.PP
+.ne 3
+.B "echo \fP[\fB-n\fP]\fB \fImessage\fP"
+.sp
+The echo command may be used to annoy 
+.I screen
+users with a 'message of the
+day'. Typically installed in a global /usr/local/etc/screenrc. See also
+\*Qsleep\*U.
+Echo is also useful for online checking of environment variables.
+.PP
+.ne 3
+.B "escape \fIxy\fP"
+.sp
+Set the command character to \fIx\fP and the character generating a literal
+command character to \fIy\fP (just like in the \-e option).
+Each argument is either a single character, a two-character sequence
+of the form \*Q^x\*U (meaning \*QC-x\*U), a backslash followed by an octal
+number (specifying the ASCII code of the character), or a backslash followed
+by a second character, such as \*Q\e^\*U or \*Q\e\e\*U.
+The default is \*Q^Aa\*U, but \*Q``\*U is recommended by one of the authors.
+.PP
+.ne 3
+.B "flow on\fP|\fBoff\fP|\fBauto \fP[\fBinterrupt\fP]\fB"
+.sp
+Sets the default flow-control mode for new windows.
+Specifying \*Qflow auto interrupt\*U is the same as the command-line options
+.B \-fa
+and
+.BR \-i . 
+See the discussion on FLOW-CONTROL later on in this document for full details
+and note, that this is subject to change in future releases.
+.PP
+.ne 3
+.B "hardcopy_append on\fP|\fBoff"
+.sp
+If set to "on", 
+.I screen
+will append to the "hardcopy.n" files created by the command \*QC-a h\*U, 
+otherwise these files are overwritten each time.
+.PP
+.ne 3
+.B "hardstatus on\fP|\fBoff"
+.sp
+Toggles the use of the terminals hardware status line. If "on", 
+.I screen
+will use this facility to display one line messages. Otherwise these messages
+are overlayed in reverse video mode at the display line. Note that the 
+hardstatus feature should only be used, if the termcap/terminfo capabilities
+"hs", "ts", "fs" and "ds" are set properly.
+.PP
+.ne 3
+.B "login on\fP|\fBoff"
+.sp
+Sets the login flag which determines if new windows should have /etc/utmp
+entries added for them.
+The login state is also changeable on-the-fly by using the bindable version
+of the \*Qlogin\*U command (C-a L) of by means of "C-a : set login on|off".
+The default should be \*Qon\*U for a 
+.I screen
+that runs under suid-root.
+.PP
+.ne 3
+.B "markkeys \fIstring\fP"
+.sp
+This is a method of changing the keymap used for copy/history mode.
+The string is made up of \fIoldchar\fP=\fInewchar\fP pairs which are
+separated by `:'. Example: The string \*QB=^B:F=^F\*U will change the 
+keys `C-b' and `C-f' from their (original emacs-style bindings) to the vi style
+binding (scroll up/down full page), which is the default meaning of `B' and
+`F'.
+.PP
+.ne 3
+.B "mode \fImode\fP"
+.sp
+The mode of each newly allocated pseudo-tty is set to \fImode\fP.
+\fIMode\fP is an octal number.
+When no \*Qmode\*U command is given, mode 0622 is used.
+.PP
+.ne 3
+.B "nethack on\fP|\fBoff"
+.sp
+Changes the kind of error messages used by
+.IR screen .
+When you are familiar with the game \*Qnethack\*U, you may enjoy the
+nethack-style messages which will often blur the facts a little, but are
+much funnier to read. Anyway, standard messages often tend to be unclear as
+well.
+.br
+This option is only 
+available, if screen was compiled with the NETHACK flag defined. The
+default setting is then determined by the presence of the environment 
+variable $NETHACKOPTIONS.
+.PP
+.ne 3
+.B "msgminwait \fIsec\fP"
+.sp
+Defines the time 
+.I screen 
+delays all activity after a message was dispayled. The default is 1 second.
+.PP
+.ne 3
+.B "msgwait \fIsec\fP"
+.sp
+Defines the time a message is displayed, if 
+.I screen
+is not disturbed by other activity. The default is 5 seconds.
+.PP
+.ne 3
+.B "password \fP[\fIcrypted_pw\fP]"
+.sp
+Present a crypted password in your \*Q.screenrc\*U file and screen will ask
+for it, whenever a detached session is tried to be resumed. This is useful,
+if you have privileged programs running under
+.I screen
+and you want to protect your session from reattach attempts by users that 
+managed to have your uid. (I.e. any superuser.)
+.PP
+.ne 3
+.B "pow_detach_msg \fImessage\fP"
+.sp
+The \fImessage\fP specified here is output whenever a `Power detach' was
+performed. It may be used as a replacement for a logout message or to reset 
+baud rate, etc.
+.PP
+.ne 3
+.B "screen \fP[\fI-opts\fP] [\fIn\fP] [\fIcmd\fP [\fIargs\fP]]"
+.sp
+Establish a new window.
+The flow-control options (\fB\-f\fP, \fB\-fn\fP and \fB\-fa\fP),
+title (a.\|k.\|a.) option (\fB\-t\fP), login options (\fB-l\fP and \fB-ln\fP)
+, terminal type option (\fB-T <term>\fP) and scrollback option (\fB-h\fP <num>)
+may be specified for each command.
+If an optional number \fIn\fP in the range 0..9 is given, the window
+number \fIn\fP is assigned to the newly created window (or, if this
+number is already in-use, the next available number).
+If a command is specified after \*Qscreen\*U, this command (with the given
+arguments) is started in the window; otherwise, a shell is created.
+Thus, if your \*Q.screenrc\*U contains the lines
+.sp
+.nf
+       # example for .screenrc:
+       screen 1
+       screen -fn -t foobar 2 telnet foobar
+.fi
+.sp
+.I screen
+creates a shell window (in window #1), a window with a TELNET connection
+to the machine foobar (with no flow-control using the a.\|k.\|a. \*Qfoobar\*U
+in window #2), and finally, a second shell window
+(the default window) which gets a window number of zero.
+When the initialization is completed,
+.I screen
+switches to the last window specified in your .screenrc file or, if none, it
+opens a default window #0 that would be displayed in this
+case.
+.PP
+.ne 3
+.B "scrollback \fP\fInum\fP"
+.sp
+Set the size of the scrollback buffer for new windows to \fInum\fP lines.
+The default scrollback is 50 lines.
+Use "C-a : set scrollback \fInum\fP" to change the scrollback size of the
+current window and use "C-a i" to view the current setting. 
+.PP
+.ne 3
+.B "redraw on\fP|\fBoff"
+.sp
+Define whether the display should be refreshed (as done with "C-a l") after
+switching to the current window. As usual when the "set" keyword is given,
+this command only affects the current window. But unlike other commands,
+"redraw off" (without "set") affects all windows, the window specific settings
+come into effect again when "redraw on" (without "set") is entered.
+.PP
+.ne 3
+.B "shell \fIcommand\fP"
+.sp
+Set the command to be used to create a new shell.
+This overrides the value of the environment variable $SHELL, or \*Q/bin/sh\*U
+if undefined.
+This is useful if you'd like to run a tty-enhancer which is expecting to
+execute the program specified in $SHELL.
+.PP
+.ne 3
+.B "shellaka \fIa.\|k.\|a.\fP"
+.sp
+Set the a.\|k.\|a. for all shells created during startup or by
+the C-A C-c command.
+For details about what a.\|k.\|a.\|'s are, see the discussion
+entitled ALSO KNOWN AS.
+.PP
+.ne
+.B "sleep \fP\fInum\fP"
+This command will pause the execution of a .screenrc file for \fInum\fP seconds.
+It may be used to give users a chance to read the messages output by \*Qecho\*U.
+.PP
+.ne 3
+.B "slowpaste \fIusec\fP"
+.sp
+Define the speed text is inserted by the paste ("C-a ]") command. For each
+80 characters (IOSIZE) pasted 
+.I screen
+will make a pause of \fIusec\fP milliseconds to allow the application the
+processing of input. Use that, if you have to fear that your underlying system
+chokes on large pastes.
+.PP
+.ne 3
+.B "term \fIterm\fP"
+.sp
+In each window's environment
+.I screen
+opens, it sets the $TERM variable to \*Qscreen\*U by default. 
+But when no description for \*Qscreen\*U is installed in the local termcap
+or terminfo data base, you can pretend that the terminal emulator is - say -
+\*Qvt100\*U. This won't do much harm, as 
+.I screen
+is VT100/ANSI compatible.
+The use of the \*Qterm\*U command is discouraged for non-default purpose.
+That is, one may want to specify special $TERM settings (e.g. vt100) for the
+next \*Qscreen rlogin othermachine\*U command. Use the command \*Qscreen -T vt100
+rlogin othermachine\*U rather than setting (\*Qterm vt100\*U) and resetting
+(\*Qterm screen\*U) the default before and after the \*Qscreen\*U command.
+.PP
+.ne 3
+.B "termcap \fIterm\fP \fIterminal-tweaks\fP \fP[\fIwindow-tweaks\fP]"
+.br
+.B "terminfo \fIterm\fP \fIterminal-tweaks\fP \fP[\fIwindow-tweaks\fP]"
+.sp
+Use this command to modify your terminal's termcap entry without going through
+all the hassles involved in creating a custom termcap entry.
+Plus, you can optionally customize the termcap generated for the windows.
+If your system works with terminfo-database rather than with
+termcap
+.I screen
+will understand the `terminfo' command which has the same effects as
+the `termcap' command. Thus users can write one .screenrc file that handles
+both cases, although terminfo syntax is slightly different
+from termcap syntax.
+.PP
+The first argument specifies which terminal(s) should be affected by this
+definition.
+You can specify multiple terminal names by separating them with `|'s.
+Use `*' to match all terminals and `vt*' to match all terminals that begin
+with \*Qvt\*U.
+.PP
+Each \fItweak\fP argument contains one or more termcap defines (separated
+by `:'s) to be inserted at the start of the appropriate termcap entry,
+enhancing it or overriding existing values.
+The first tweak modifies your terminal's termcap, and contains definitions
+that your terminal uses to perform certain functions.
+Specify a null string to leave this unchanged (e.\|g. '').
+The second (optional) tweak modifies all the window termcaps, and should
+contain definitions that screen understands (see the \*QVIRTUAL TERMINAL\*U
+section).
+.PP
+Some examples:
+.IP
+termcap xterm*  LP:hs@
+.PP
+Informs
+.I screen
+that all terminals that begin with `xterm' have firm auto-margins that
+allow the last position on the screen to be updated (LP), but they don't
+really have a status line (no 'hs' -- append `@' to turn entries off).
+Note that we assume `LP' for all terminal names that start with \*Qvt\*U,
+but only if you don't specify a termcap command for that terminal.
+.sp
+.nf
+       termcap vt*  LP
+       termcap vt102|vt220  Z0=\eE[?3h:Z1=\eE[?3l
+.fi
+.sp
+Specifies the firm-margined `LP' capability for all terminals that begin with
+`vt', and the second line will also add the escape-sequences to switch
+into (Z0) and back out of (Z1) 132-character-per-line mode if this is
+a vt102 or vt220.
+(You must specify Z0 and Z1 in your termcap to use the width-changing
+commands.)
+.IP
+termcap vt100  ""  l0=PF1:l1=PF2:l2=PF3:l3=PF4
+.PP
+This leaves your vt100 termcap alone and adds the function key labels to
+each window's termcap entry.
+.IP
+termcap h19|z19  am@:im=\eE@:ei=\eEO  dc=\eE[P
+.PP
+Takes a h19 or z19 termcap and turns off auto-margins (am@) and enables the
+insert mode (im) and end-insert (ei) capabilities (the `@' in the `im'
+string is after the `=', so it is part of the string).
+Having the `im' and `ei' definitions put into your terminal's termcap will
+cause screen to automatically advertise the character-insert capability in
+each window's termcap.
+Each window will also get the delete-character capability (dc) added to its
+termcap, which screen will translate into a line-update for the terminal
+(we're pretending it doesn't support character deletion).
+.PP
+If you would like to fully specify each window's termcap entry, you should
+instead set the $SCREENCAP variable prior to running
+.IR screen .
+See the discussion on the \*QVIRTUAL TERMINAL\*U in this manual, and the termcap(5)
+man page for more information on termcap definitions.
+.PP
+.ne 3
+.B "vbell on\fP|\fBoff"
+.sp
+Sets the visual bell setting for new windows. If your terminal does not support
+a visual bell a message is printed to the status line. The default 
+message is \*QWuff, Wuff!!\*U.
+.PP
+.ne 3
+.B "vbell_msg \fImessage\fP"
+.sp
+Sets the visual bell message. \fImessage\fP is printed to the status line if
+the window receives a bell character (^G) and vbell is set to \*Qon\*U.
+.PP
+.ne 3
+.B "vbellwait \fIsec\fP"
+.sp
+Define a delay in seconds after each display of 
+.I screen 's
+visual bell message. The default is 0 seconds.
+.PP
+.ne 3
+.B "wrap on\fP|\fBoff"
+.sp
+Sets the line-wrap setting for new windows.
+When line-wrap is on, the second consecutive printable character output at
+the last column of a line will wrap to the start of the following line.
+As an added feature, backspace (^H) will also wrap through the left margin
+to the previous line.
+Line-wrap is on by default and can be toggled with the \*Qwrap\*U
+command (\*QC-a r\*U) or by means of "C-a : set wrap on|off".
+.SH "THE MESSAGE LINE"
+.I Screen
+displays informational messages and other diagnostics in a \fImessage line\fP
+at the bottom of the screen.
+If your terminal has a status line defined in its termcap, screen will use
+this for displaying its messages, otherwise the last line of the screen will
+be temporarily overwritten and output will be momentarily interrupted.
+The message line is automatically removed after a few seconds delay, but it
+can also be removed early (on terminals without a status line) by beginning
+to type.
+.PP
+The message line facility can be used by an application running in
+the current window by means of the ANSI \fIPrivacy message\fP
+control sequence.
+For instance, from within the shell, try something like:
+.IP
+echo '<esc>^Hello world<esc>\e\e'
+.PP
+where '<esc>' is an \fIescape\fP, '^' is a literal up-arrow,
+and '\e\e' turns into a single backslash.
+.SH "FLOW-CONTROL"
+Each window has a flow-control setting that determines how screen deals with
+the XON and XOFF characters (and perhaps the interrupt character).
+When flow-control is turned off, screen ignores the XON and XOFF characters,
+which allows the user to send them to the current program by simply typing
+them (useful for the \fIemacs\fP editor, for instance).
+The trade-off is that it will take longer for output from a \*Qnormal\*U
+program to pause in response to an XOFF.
+With flow-control turned on, XON and XOFF characters are used to immediately
+pause the output of the current window.
+You can still send these characters to the current program, but you must use
+the appropriate two-character screen commands (typically \*QC-a q\*U (xon)
+and \*QC-a s\*U (xoff)).
+The xon/xoff commands are also useful for typing C-s and C-q past a terminal
+that intercepts these characters.
+.PP
+Each window has an initial flow-control value set with either the
+.B \-f
+option or the \*Qflow\*U .screenrc command. Per default the windows
+are set to automatic flow-switching.
+It can then be toggled between the three states 'fixed on', 'fixed off' and
+'automatic' interactively with the \*Qflow\*U command bound to "C-a f".
+.PP
+The automatic flow-switching mode deals with
+flow control using the TIOCPKT mode (like \*Qrlogin\*U does). If
+the tty driver does not support TIOCPKT, screen tries to find out
+the right mode based on the current setting of the application
+keypad -- when it is enabled, flow-control is turned off and visa versa.
+Of course, you can still manipulate flow-control manually when needed.
+.PP
+If you're running with flow-control enabled and find that pressing the
+interrupt key (usually C-c) does not interrupt the display until another
+6-8 lines have scrolled by, try running screen with the \*Qinterrupt\*U
+option (add the \*Qinterrupt\*U flag to the \*Qflow\*U command in
+your .screenrc, or use the
+.B \-i
+command-line option).
+This causes the output that
+.I screen
+has accumulated from the interrupted program to be flushed.
+One disadvantage is that the virtual terminal's memory contains the
+non-flushed version of the output, which in rare cases can cause
+minor inaccuracies in the output.
+For example, if you switch screens and return, or update the screen
+with \*QC-a l\*U you would see the version of the output you would
+have gotten without \*Qinterrupt\*U being on.
+Also, you might need to turn off flow-control (or use auto-flow mode to turn
+it off automatically) when running a program that expects you to type the
+interrupt character as input, as it is possible to interrupt
+the output of the virtual terminal to your physical terminal when flow-control
+is enabled.
+If this happens, a simple refresh of the screen with \*QC-a l\*U will
+restore it.
+Give each mode a try, and use whichever mode you find more comfortable.
+.SH "ALSO KNOWN AS (A.\|K.\|A.\|s)"
+You can customize each window's name in the window display (viewed with the
+\*Qwindows\*U command (C-a w)) by setting it with one of
+the a.\|k.\|a. commands.
+Normally the name displayed is the actual command name of the program
+created in the window.
+However, it is sometimes useful to distinguish various programs of the same
+name or to change the name on-the-fly to reflect the current state of
+the window.
+.PP
+The default name for all shell windows can be set with the \*Qshellaka\*U
+command in the .screenrc file, while all other windows are created with
+a \*Qscreen\*U command and thus can have their name set with the
+.B \-t
+option.
+Interactively, there is the AKA-string escape-sequence
+(<esc>k\fIname\fP<esc>\e) and the \*Qaka\*U command (C-a A).
+The former can be output from an application to control the window's name
+under software control, and the latter will prompt for a name when typed.
+You can also bind pre-defined names to keys with the \*Qaka\*U command
+to set things quickly without prompting.
+.PP
+Finally,
+.I screen
+has a shell-specific heuristic that is enabled by setting the window's name
+to \*Q\fIsearch|name\fP\*U and arranging to have a null aka escape-sequence
+output as a part of your prompt.
+The \fIsearch\fP portion specifies an end-of-prompt search string, while
+the \fIname\fP portion specifies the default shell name for the window.
+If the \fIname\fP ends in a `:'
+.I screen
+will add what it believes to be the current command running in the window
+to the end of the window's shell name (e.\|g. \*Q\fIname:cmd\fP\*U).
+Otherwise the current command name supersedes the shell name while it is
+running.
+.PP
+Here's how it works:  you must modify your shell prompt to output a null
+aka escape-sequence (<esc>k<esc>\e) as a part of your prompt.
+The last part of your prompt must be the same as the string you specified
+for the \fIsearch\fP portion of the a.\|k.\|a.
+Once this is set up,
+.I screen
+will use the aka escape-sequence to clear the previous command name and
+get ready for the next command.
+Then, when a newline is received from the shell, a search is made for the
+end of the prompt.
+If found, it will grab the first word after the matched string and use it
+as the command name.
+If the command name begins with either '!', '%', or '^'
+.I screen
+will use the first word on the following line (if found) in preference to
+the just-found name.
+This helps csh users get better command names when using job control or
+history recall commands.
+.PP
+Here's some .screenrc examples:
+.IP
+screen -t top 2 nice top
+.PP
+Adding this line to your .screenrc would start a niced version of the
+\*Qtop\*U command in window 2 name \*Qtop\*U rather than \*Qnice\*U.
+.sp
+.nf
+       shellaka '> |csh'
+       screen 1
+.fi
+.sp
+This file would start two shells (one specified, one default) using
+the given shellaka.
+The a.\|k.\|a. specified is an auto-aka that would expect the prompt and
+the typed command to look something like the following:
+.IP
+/usr/joe/src/dir> trn
+.PP
+(it looks after the '> ' for the command name).
+The window status would show the name \*Qtrn\*U while the command was
+running, and revert to \*Qcsh\*U upon completion.
+.IP
+bind R screen -t '% |root:' su
+.PP
+Having this command in your .screenrc would bind the key
+sequence \*QC-a R\*U to the \*Qsu\*U command and give it an
+auto-aka name of \*Qroot:\*U.
+For this auto-aka to work, the screen could look something
+like this:
+.sp
+.nf
+       % !em
+       emacs file.c
+.fi
+.sp
+Here the user typed the csh history command \*Q!em\*U which ran the
+previously entered \*Qemacs\*U command.
+The window status would show \*Qroot:emacs\*U during the execution
+of the command, and revert to simply \*Qroot:\*U at its completion.
+.PP
+.nf
+       bind o aka
+       bind E aka ""
+       bind u aka (unknown)
+.fi
+.sp
+The first binding doesn't have any arguments, so it would prompt you
+for an a.\|k.\|a. when you type \*QC-a o\*U.
+The second binding would clear an auto-aka's current setting (C-a E).
+The third binding would set the current window's a.\|k.\|a. to \*Q(unknown)\*U
+(C-a u).
+.PP
+One thing to keep in mind when adding a null aka escape-sequence to
+your prompt is that some shells (like the csh) count all the non-control
+characters as part of the prompt's length.
+If these invisible characters aren't a multiple of 8 then backspacing over
+a tab will result in an incorrect display.
+One way to get around this is to use a prompt like this:
+.IP
+set prompt='^[[0000m^[k^[\e% '
+.PP
+The escape-sequence \*Q<esc>[0000m\*U not only normalizes the character
+attributes, but all the zeros round the length of the invisible characters
+up to 8.
+Bash users will probably want to echo the escape sequence in the
+PROMPT_COMMAND:
+.IP
+PROMPT_COMMAND='echo -n -e "\e033k\e033\e134"'
+.PP
+(I used \*Q\134\*U to output a `\e' because of a bug in v1.04).
+.SH "THE VIRTUAL TERMINAL"
+Usually
+.I screen
+tries to emulate as much of the VT100/ANSI standard
+as possible. But if your terminal lacks certain capabilities
+the emulation may not be complete. In these cases
+.I screen
+has to tell the applications that some of the features
+are missing. This is no problem on machines using termcap,
+because
+.I screen
+can use the $TERMCAP variable to
+customize the standard screen termcap.
+.br
+But if you do a
+rlogin on another machine or your machine supports only
+terminfo this method fails. Because of this
+.I screen
+offers a way to deal with these cases. Here is how it works:
+.br
+When 
+.I screen
+tries to figure out a terminal name for itself,
+it first looks
+for an entry named \*Qscreen.<term>\*U, where <term> is
+the contents of your $TERM variable.
+If no such entry exists,
+.I screen
+tries \*Qscreen\*U (or \*Qscreen-w\*U, if the terminal is wide
+(132 cols or more)).
+If even this entry cannot be found, \*Qvt100\*U is used as a
+substitute.
+.br
+The idea is that if you have a terminal which doesn't
+support an important feature (e.g. delete char or clear to EOS)
+you can build a new termcap/terminfo entry for
+.I screen
+(named \*Qscreen.<dumbterm>\*U) in which this capability
+has been disabled.  If this entry is installed on your
+machines you are able to do
+a rlogin and still keep the correct termcap/terminfo entry.
+The terminal name is put in the $TERM variable
+of all new windows.
+.I Screen
+also sets the $TERMCAP variable reflecting the capabilities
+of the virtual terminal emulated. Notice that, however, on machines
+using the terminfo database this variable has no effect.
+Furthermore, the variable $WINDOW is set to the window number
+of each window.
+.br
+The actual set of capabilities supported by the virtual terminal
+depends on the capabilities supported by the physical terminal.
+If, for instance, the physical terminal does not support underscore mode,
+.I screen
+does not put the `us' and `ue' capabilities into the window's $TERMCAP
+variable, accordingly.
+However, a minimum number of capabilities must be supported by a
+terminal in order to run
+.IR screen ;
+namely scrolling, clear screen, and direct cursor addressing
+(in addition,
+.I screen
+does not run on hardcopy terminals or on terminals that over-strike).
+.PP
+Also, you can customize the $TERMCAP value used by
+.I screen
+by using the \*Qtermcap\*U .screenrc command, or
+by defining the variable $SCREENCAP prior to startup.
+When the latter defined, its value will be copied verbatim into each
+window's $TERMCAP variable.
+This can either be the full terminal definition, or a filename where the
+terminal \*Qscreen\*U (and/or \*Qscreen-w\*U) is defined.
+.PP
+Note that 
+.I screen
+honors the \*Qterminfo\*U .screenrc command if the system uses the
+terminfo database rather than termcap.
+.PP
+When the boolean `G0' capability is present in the termcap entry
+for the terminal on which
+.I screen
+has been called, the terminal emulation of
+.I screen
+supports multiple character sets.
+This allows an application to make use of, for instance,
+the VT100 graphics character set or national character sets.
+The following control functions from ISO 2022 are supported:
+\fIlock shift G0\fP (\fISI\fP), \fIlock shift G1\fP (\fISO\fP),
+\fIlock shift G2\fP, \fIlock shift G3\fP, \fIsingle shift G2\fP,
+and \fIsingle shift G3\fP.
+When a virtual terminal is created or reset, the ASCII character
+set is designated as \fIG0\fP through \fIG3\fP.
+When the `G0' capability is present, screen evaluates the capabilities
+`S0', `E0', and `C0' if present. `S0' is the sequence the terminal uses
+to enable and start the graphics character set rather than \fISI\fP. 
+`E0' is the corresponding replacement for \fISO\fP. `C0' gives a character
+by character translation string that is used during semi-graphics mode. This 
+string is built like the `acsc' terminfo capability.
+.PP
+When the `po' and `pf' capabilities are present in the terminal's
+termcap entry, applications running in a
+.I screen
+window can send output to the printer port of the terminal.
+This allows a user to have an application in one window
+sending output to a printer connected to the terminal, while all
+other windows are still active (the printer port is enabled
+and disabled again for each chunk of output).
+As a side-effect, programs running in different windows can
+send output to the printer simultaneously.
+Data sent to the printer is not displayed in the window.
+.PP
+Some capabilities are only put into the $TERMCAP
+variable of the virtual terminal if they can be efficiently
+implemented by the physical terminal.
+For instance, `dl' (delete line) is only put into the $TERMCAP
+variable if the terminal supports either delete line itself or
+scrolling regions. Note that this may provoke confusion, when 
+the session is reattached on a different terminal, as the value
+of $TERMCAP cannot be modified by parent processes.
+.PP
+The following is a list of control sequences recognized by
+.IR screen .
+\*Q(V)\*U and \*Q(A)\*U indicate VT100-specific and ANSI- or
+ISO-specific functions, respectively.
+.PP
+.nf
+.TP 20
+.B "ESC E"
+       Next Line
+.TP 20
+.B "ESC D"
+       Index
+.TP 20
+.B "ESC M"
+       Reverse Index
+.TP 20
+.B "ESC H"
+       Horizontal Tab Set
+.TP 20
+.B "ESC 7"
+(V)    Save Cursor and Attributes
+.TP 20
+.B "ESC 8"
+(V)    Restore Cursor and Attributes
+.TP 20
+.B "ESC [s"
+(A)    Save Cursor and Attributes
+.TP 20
+.B "ESC [u"
+(A)    Restore Cursor and Attributes
+.TP 20
+.B "ESC c"
+       Reset to Initial State
+.TP 20
+.B "ESC ="
+(V)    Application Keypad Mode
+.TP 20
+.B "ESC >"
+(V)    Numeric Keypad Mode
+.TP 20
+.B "ESC # 8"
+(V)    Fill Screen with E's
+.TP 20
+.B "ESC \e"
+(A)    String Terminator
+.TP 20
+.B "ESC ^"
+(A)    Privacy Message String (Message Line)
+.TP 20
+.B "ESC k"
+       A.\|k.\|a. Definition String
+.TP 20
+.B "ESC P"
+(A)    Device Control String
+       Outputs a string directly to the host
+       terminal without interpretation.
+.TP 20
+.B "ESC _"
+(A)    Application Program Command (not used)
+.TP 20
+.B "ESC ]"
+(A)    Operating System Command (not used)
+.TP 20
+.B "Control-N"
+(A)    Lock Shift G1 (SO)
+.TP 20
+.B "Control-O"
+(A)    Lock Shift G0 (SI)
+.TP 20
+.B "ESC n"
+(A)    Lock Shift G2
+.TP 20
+.B "ESC o"
+(A)    Lock Shift G3
+.TP 20
+.B "ESC N"
+(A)    Single Shift G2
+.TP 20
+.B "ESC O"
+(A)    Single Shift G3
+.TP 20
+.B "ESC ( \fPPcs"
+(A)    Designate character set as G0
+.TP 20
+.B "ESC ) \fPPcs"
+(A)    Designate character set as G1
+.TP 20
+.B "ESC * \fPPcs"
+(A)    Designate character set as G2
+.TP 20
+.B "ESC + \fPPcs"
+(A)    Designate character set as G3
+.TP 20
+.B "ESC [ \fPPn\fB ; \fPPn\fB H"
+       Direct Cursor Addressing
+.TP 20
+.B "ESC [ \fPPn\fB ; \fPPn\fB f"
+       Direct Cursor Addressing
+.TP 20
+.B "ESC [ \fPPn\fB J"
+       Erase in Display
+.TP 20
+\h'\w'ESC 'u'Pn = None or \fB0\fP
+       From Cursor to End of Screen
+.TP 20
+\h'\w'ESC Pn = 'u'\fB1\fP
+       From Beginning of Screen to Cursor
+.TP 20
+\h'\w'ESC Pn = 'u'\fB2\fP
+       Entire Screen
+.TP 20
+.B "ESC [ \fPPn\fB K"
+       Erase in Line
+.TP 20
+\h'\w'ESC 'u'Pn = None or \fB0\fP
+       From Cursor to End of Line
+.TP 20
+\h'\w'ESC Pn = 'u'\fB1\fP
+       From Beginning of Line to Cursor
+.TP 20
+\h'\w'ESC Pn = 'u'\fB2\fP
+       Entire Line
+.TP 20
+.B "ESC [ \fPPn\fB A"
+       Cursor Up
+.TP 20
+.B "ESC [ \fPPn\fB B"
+       Cursor Down
+.TP 20
+.B "ESC [ \fPPn\fB C"
+       Cursor Right
+.TP 20
+.B "ESC [ \fPPn\fB D"
+       Cursor Left
+.TP 20
+.B "ESC [ \fPPs\fB ;\fP...\fB; \fPPs\fB m"
+       Select Graphic Rendition
+.TP 20
+\h'\w'ESC 'u'Ps = None or \fB0\fP
+       Default Rendition
+.TP 20
+\h'\w'ESC Ps = 'u'\fB1\fP
+       Bold
+.TP 20
+\h'\w'ESC Ps = 'u'\fB2\fP
+(A)    Faint
+.TP 20
+\h'\w'ESC Ps = 'u'\fB3\fP
+(A)    \fIStandout\fP Mode (ANSI: Italicized)
+.TP 20
+\h'\w'ESC Ps = 'u'\fB4\fP
+       Underlined
+.TP 20
+\h'\w'ESC Ps = 'u'\fB5\fP
+       Blinking
+.TP 20
+\h'\w'ESC Ps = 'u'\fB7\fP
+       Negative Image
+.TP 20
+\h'\w'ESC Ps = 'u'\fB22\fP
+(A)    Normal Intensity
+.TP 20
+\h'\w'ESC Ps = 'u'\fB23\fP
+(A)    \fIStandout\fP Mode off (ANSI: Italicized off)
+.TP 20
+\h'\w'ESC Ps = 'u'\fB24\fP
+(A)    Not Underlined
+.TP 20
+\h'\w'ESC Ps = 'u'\fB25\fP
+(A)    Not Blinking
+.TP 20
+\h'\w'ESC Ps = 'u'\fB27\fP
+(A)    Positive Image
+.TP 20
+.B "ESC [ \fPPn\fB g"
+       Tab Clear
+.TP 20
+\h'\w'ESC 'u'Pn = None or \fB0\fP
+       Clear Tab at Current Position
+.TP 20
+\h'\w'ESC Ps = 'u'\fB3\fP
+       Clear All Tabs
+.TP 20
+.B "ESC [ \fPPn\fB ; \fPPn\fB r"
+(V)    Set Scrolling Region
+.TP 20
+.B "ESC [ \fPPn\fB I"
+(A)    Horizontal Tab
+.TP 20
+.B "ESC [ \fPPn\fB Z"
+(A)    Backward Tab
+.TP 20
+.B "ESC [ \fPPn\fB L"
+(A)    Insert Line
+.TP 20
+.B "ESC [ \fPPn\fB M"
+(A)    Delete Line
+.TP 20
+.B "ESC [ \fPPn\fB @"
+(A)    Insert Character
+.TP 20
+.B "ESC [ \fPPn\fB P"
+(A)    Delete Character
+.TP 20
+.B "ESC [ \fPPs\fB ;\fP...\fB; \fPPs\fB h"
+       Set Mode
+.TP 20
+.B "ESC [ \fPPs\fB ;\fP...\fB; \fPPs\fB l"
+       Reset Mode
+.TP 20
+\h'\w'ESC 'u'Ps = \fB4\fP
+(A)    Insert Mode
+.TP 20
+\h'\w'ESC Ps = 'u'\fB?3\fP
+(V)    Change Terminal Width
+.TP 20
+\h'\w'ESC Ps = 'u'\fB?5\fP
+(V)    Visible Bell (\fIOn\fP followed by \fIOff\fP)
+.TP 20
+\h'\w'ESC Ps = 'u'\fB?6\fP
+(V)    \fIOrigin\fP Mode
+.TP 20
+\h'\w'ESC Ps = 'u'\fB?7\fP
+(V)    \fIWrap\fP Mode
+.TP 20
+.B "ESC [ 5 i"
+(A)    Start relay to printer (ANSI Media Copy)
+.TP 20
+.B "ESC [ 4 i"
+(A)    Stop relay to printer (ANSI Media Copy)
+.fi
+.SH FILES
+.nf
+.ta 2i
+$SYSSCREENRC
+.br
+/local/etc/screenrc              \fIscreen\fP initialization commands
+.br
+$ISCREENRC
+.br
+$SCREENRC
+.br
+$HOME/.iscreenrc
+.br
+$HOME/.screenrc          Read in after /usr/local/etc/screenrc
+.br
+$ISCREENDIR/S-<login>
+.br
+$SCREENDIR/S-<login>
+.br
+/local/screens/S-<login>                 Socket directories (default)
+.br
+/usr/tmp/screens/S-<login>               Alternate socket directories.
+.br
+<socket directory>/.termcap              Written by the "termcap" output function
+.br
+/usr/tmp/screens/screen-exchange                 or
+.br
+/tmp/screen-exchange             \fIscreen\fP `interprocess communication buffer'
+.br
+hardcopy.[0-9]   Screen images created by the hardcopy function
+.br
+screenlog.[0-9]          Output log files created by the log function
+.br
+/usr/lib/terminfo/?/*             or
+.br
+/etc/termcap     Terminal capability databases
+.br
+/etc/utmp        Login records
+.br
+$LOCKPRG         Program that locks a terminal.
+.fi
+.SH "SEE ALSO"
+termcap(5), utmp(5), vi(1), captoinfo(1), tic(1)
+.SH AUTHORS
+Originally created by Oliver Laumann, this latest version was
+produced by Wayne Davison, Juergen Weigert and Michael Schroeder.
+.SH CONTRIBUTORS
+Allan Ball,
+Bart Schaefer,
+Doug Siebert,
+Howard Chu,
+Jay Vassos-Libove,  
+John Kraft,
+Larry Virden,
+Marc Boucher,
+Nathan Glasser,
+Patrick Wolfe,
+Rudolf Koenig.
+Toerless Eckert, 
+.SH VERSION
+This is version 3.2. It's roots are a merge of a custom version
+2.3PR7 by Wayne Davison
+and several enhancements to Oliver Laumann's version 2.0. Note that all versions
+numbered 2.x are copyright by Oliver Laumann. 
+
+.SH BUGS
+`dm' (delete mode), `xn', and `xs' are not handled
+correctly (they are ignored).
+.PP
+The \fIGR\fP set of ISO 2022 is not supported.
+.PP
+There is no keyboard input translation to VT100 sequences.
+.PP
+It is not possible to change the environment variable $TERMCAP when 
+reattaching under a different terminal type.
+.PP
+The support of terminfo based systems is very limited. Adding extra
+capabilities to $TERMCAP may not have any effects.
+.PP
+.I Screen
+does not make use of hardware tabs.
+.PP
+.I Screen
+must be installed as set-uid with owner root in order to be able
+to correctly change the owner of the tty device file for each
+window.
+Special permission may also be required to write the file \*Q/etc/utmp\*U.
+.PP
+Entries in \*Q/etc/utmp\*U are not removed when
+.I screen
+is killed with SIGKILL.
+This will cause some programs (like "w" or "rwho")
+to advertise that a user is logged on who really isn't.