ignore & before array
[unix-history] / usr / src / old / more / more.c
index 0d84b2b..f7b6689 100644 (file)
@@ -1,4 +1,24 @@
-static char *sccsid = "@(#)more.c      4.8 (Berkeley) 83/02/09";
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific written prior permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1980 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)more.c     5.18 (Berkeley) %G%";
+#endif /* not lint */
 
 /*
 ** more.c - General purpose tty output filter and file perusal program
 
 /*
 ** more.c - General purpose tty output filter and file perusal program
@@ -10,19 +30,19 @@ static      char *sccsid = "@(#)more.c      4.8 (Berkeley) 83/02/09";
 */
 
 #include <stdio.h>
 */
 
 #include <stdio.h>
+#include <sys/param.h>
 #include <ctype.h>
 #include <signal.h>
 #include <errno.h>
 #include <sgtty.h>
 #include <setjmp.h>
 #include <ctype.h>
 #include <signal.h>
 #include <errno.h>
 #include <sgtty.h>
 #include <setjmp.h>
-#include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
-#include <local/uparm.h>
+#include <sys/file.h>
+#include <a.out.h>
+#include <varargs.h>
 
 
-/* Help file will eventually go in libpath(more.help) on all systems */
-
-#define HELPFILE       libpath(more.help)
-#define VI             binpath(vi)
+#define HELPFILE       "/usr/lib/more.help"
+#define VI             "/usr/ucb/vi"
 
 #define Fopen(s,m)     (Currline = 0,file_pos=0,fopen(s,m))
 #define Ftell(f)       file_pos
 
 #define Fopen(s,m)     (Currline = 0,file_pos=0,fopen(s,m))
 #define Ftell(f)       file_pos
@@ -35,15 +55,15 @@ static      char *sccsid = "@(#)more.c      4.8 (Berkeley) 83/02/09";
 
 #define TBUFSIZ        1024
 #define LINSIZ 256
 
 #define TBUFSIZ        1024
 #define LINSIZ 256
-#define ctrl(letter)   ('letter' & 077)
+#define ctrl(letter)   (letter & 077)
 #define RUBOUT '\177'
 #define ESC    '\033'
 #define QUIT   '\034'
 
 #define RUBOUT '\177'
 #define ESC    '\033'
 #define QUIT   '\034'
 
-struct sgttyb  otty;
+struct sgttyb  otty, savetty;
 long           file_pos, file_size;
 int            fnum, no_intty, no_tty, slow_tty;
 long           file_pos, file_size;
 int            fnum, no_intty, no_tty, slow_tty;
-int            dum_opt, dlines, onquit(), end_it();
+int            dum_opt, dlines, onquit(), end_it(), chgwinsz();
 int            onsusp();
 int            nscroll = 11;   /* Number of lines scrolled by 'd' */
 int            fold_opt = 1;   /* Fold long lines */
 int            onsusp();
 int            nscroll = 11;   /* Number of lines scrolled by 'd' */
 int            fold_opt = 1;   /* Fold long lines */
@@ -55,11 +75,13 @@ int         Currline;       /* Line we are currently at */
 int            startup = 1;
 int            firstf = 1;
 int            notell = 1;
 int            startup = 1;
 int            firstf = 1;
 int            notell = 1;
+int            docrterase = 0;
+int            docrtkill = 0;
 int            bad_so; /* True if overwriting does not turn off standout */
 int            inwait, Pause, errors;
 int            within; /* true if we are within a file,
                        false if we are between files */
 int            bad_so; /* True if overwriting does not turn off standout */
 int            inwait, Pause, errors;
 int            within; /* true if we are within a file,
                        false if we are between files */
-int            hard, dumb, noscroll, hardtabs, clreol;
+int            hard, dumb, noscroll, hardtabs, clreol, eatnl;
 int            catch_susp;     /* We should catch the SIGTSTP signal */
 char           **fnames;       /* The list of file names */
 int            nfiles;         /* Number of files left to process */
 int            catch_susp;     /* We should catch the SIGTSTP signal */
 char           **fnames;       /* The list of file names */
 int            nfiles;         /* Number of files left to process */
@@ -67,7 +89,6 @@ char          *shell;         /* The name of the shell to use */
 int            shellp;         /* A previous shell command exists */
 char           ch;
 jmp_buf                restore;
 int            shellp;         /* A previous shell command exists */
 char           ch;
 jmp_buf                restore;
-char           obuf[BUFSIZ];   /* stdout buffer */
 char           Line[LINSIZ];   /* Line buffer */
 int            Lpp = 24;       /* lines per page */
 char           *Clear;         /* clear screen */
 char           Line[LINSIZ];   /* Line buffer */
 int            Lpp = 24;       /* lines per page */
 char           *Clear;         /* clear screen */
@@ -83,6 +104,9 @@ char         *EodClr;        /* clear rest of screen */
 char           *tgetstr();
 int            Mcol = 80;      /* number of columns */
 int            Wrap = 1;       /* set if automargins */
 char           *tgetstr();
 int            Mcol = 80;      /* number of columns */
 int            Wrap = 1;       /* set if automargins */
+int            soglitch;       /* terminal has standout mode glitch */
+int            ulglitch;       /* terminal has underline mode glitch */
+int            pstate = 0;     /* current UL state */
 long           fseek();
 char           *getenv();
 struct {
 long           fseek();
 char           *getenv();
 struct {
@@ -101,7 +125,7 @@ char *argv[];
     register char      *p;
     register char      ch;
     register int       left;
     register char      *p;
     register char      ch;
     register int       left;
-    int                        prnames = 0; 
+    int                        prnames = 0;
     int                        initopt = 0;
     int                        srchopt = 0;
     int                        clearit = 0;
     int                        initopt = 0;
     int                        srchopt = 0;
     int                        clearit = 0;
@@ -112,6 +136,9 @@ char *argv[];
     nfiles = argc;
     fnames = argv;
     initterm ();
     nfiles = argc;
     fnames = argv;
     initterm ();
+    nscroll = Lpp/2 - 1;
+    if (nscroll <= 0)
+       nscroll = 1;
     if(s = getenv("MORE")) argscan(s);
     while (--nfiles > 0) {
        if ((ch = (*++fnames)[0]) == '-') {
     if(s = getenv("MORE")) argscan(s);
     while (--nfiles > 0) {
        if ((ch = (*++fnames)[0]) == '-') {
@@ -140,19 +167,23 @@ char *argv[];
      */
     if(clreol)
     {
      */
     if(clreol)
     {
-       if ((*Home == '\0') || (*eraseln == '\0') || (*EodClr == '\0'))
-           clreol = 0;
+        if((Home == NULL) || (*Home == '\0') ||
+          (eraseln == NULL) || (*eraseln == '\0') ||
+           (EodClr == NULL) || (*EodClr == '\0') )
+             clreol = 0;
        else noscroll = 1;
     }
        else noscroll = 1;
     }
-
     if (dlines == 0)
        dlines = Lpp - (noscroll ? 1 : 2);
     left = dlines;
     if (nfiles > 1)
        prnames++;
     if (!no_intty && nfiles == 0) {
     if (dlines == 0)
        dlines = Lpp - (noscroll ? 1 : 2);
     left = dlines;
     if (nfiles > 1)
        prnames++;
     if (!no_intty && nfiles == 0) {
-       fputs("Usage: ",stderr);
-       fputs(argv[0],stderr);
+       char *rindex();
+
+       p = rindex(argv[0], '/');
+       fputs("usage: ",stderr);
+       fputs(p ? p + 1 : argv[0],stderr);
        fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr);
        exit(1);
     }
        fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr);
        exit(1);
     }
@@ -161,11 +192,12 @@ char *argv[];
     if (!no_tty) {
        signal(SIGQUIT, onquit);
        signal(SIGINT, end_it);
     if (!no_tty) {
        signal(SIGQUIT, onquit);
        signal(SIGINT, end_it);
+       signal(SIGWINCH, chgwinsz);
        if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) {
            signal(SIGTSTP, onsusp);
            catch_susp++;
        }
        if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) {
            signal(SIGTSTP, onsusp);
            catch_susp++;
        }
-       stty (2, &otty);
+       stty (fileno(stderr), &otty);
     }
     if (no_intty) {
        if (no_tty)
     }
     if (no_intty) {
        if (no_tty)
@@ -218,7 +250,7 @@ char *argv[];
                left = command (fnames[fnum], f);
            }
            if (left != 0) {
                left = command (fnames[fnum], f);
            }
            if (left != 0) {
-               if ((noscroll || clearit) && (file_size != 0x7fffffffffffffffL))
+               if ((noscroll || clearit) && (file_size != LONG_MAX))
                    if (clreol)
                        home ();
                    else
                    if (clreol)
                        home ();
                    else
@@ -235,7 +267,7 @@ char *argv[];
                    if(clreol) cleareol();
                    printf("%s\n", fnames[fnum]);
                    if(clreol) cleareol();
                    if(clreol) cleareol();
                    printf("%s\n", fnames[fnum]);
                    if(clreol) cleareol();
-                   printf("::::::::::::::\n", fnames[fnum]);
+                   printf("::::::::::::::\n");
                    if (left > Lpp - 4)
                        left = Lpp - 4;
                }
                    if (left > Lpp - 4)
                        left = Lpp - 4;
                }
@@ -263,23 +295,44 @@ char *argv[];
 argscan(s)
 char *s;
 {
 argscan(s)
 char *s;
 {
-           for (dlines = 0; *s != '\0'; s++)
-               if (isdigit(*s))
-                   dlines = dlines*10 + *s - '0';
-               else if (*s == 'd')
-                   dum_opt = 1;
-               else if (*s == 'l')
-                   stop_opt = 0;
-               else if (*s == 'f')
-                   fold_opt = 0;
-               else if (*s == 'p')
-                   noscroll++;
-               else if (*s == 'c')
-                   clreol++;
-               else if (*s == 's')
-                   ssp_opt = 1;
-               else if (*s == 'u')
-                   ul_opt = 0;
+       int seen_num = 0;
+
+       while (*s != '\0') {
+               switch (*s) {
+                 case '0': case '1': case '2':
+                 case '3': case '4': case '5':
+                 case '6': case '7': case '8':
+                 case '9':
+                       if (!seen_num) {
+                               dlines = 0;
+                               seen_num = 1;
+                       }
+                       dlines = dlines*10 + *s - '0';
+                       break;
+                 case 'd':
+                       dum_opt = 1;
+                       break;
+                 case 'l':
+                       stop_opt = 0;
+                       break;
+                 case 'f':
+                       fold_opt = 0;
+                       break;
+                 case 'p':
+                       noscroll++;
+                       break;
+                 case 'c':
+                       clreol++;
+                       break;
+                 case 's':
+                       ssp_opt = 1;
+                       break;
+                 case 'u':
+                       ul_opt = 0;
+                       break;
+               }
+               s++;
+       }
 }
 
 
 }
 
 
@@ -290,55 +343,65 @@ char *s;
 
 FILE *
 checkf (fs, clearfirst)
 
 FILE *
 checkf (fs, clearfirst)
-register char *fs;
-int *clearfirst;
+       register char *fs;
+       int *clearfirst;
 {
 {
-    struct stat stbuf;
-    register FILE *f;
-    char c;
+       struct stat stbuf;
+       register FILE *f;
+       char c;
 
 
-    if (stat (fs, &stbuf) == -1) {
-       fflush(stdout);
-       if (clreol)
-           cleareol ();
-       perror(fs);
-       return (NULL);
-    }
-    if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
-       printf("\n*** %s: directory ***\n\n", fs);
-       return (NULL);
-    }
-    if ((f=Fopen(fs, "r")) == NULL) {
-       fflush(stdout);
-       perror(fs);
-       return (NULL);
-    }
-    c = Getc(f);
-
-    /* Try to see whether it is an ASCII file */
-
-    switch ((c | *f->_ptr << 8) & 0177777) {
-    case 0405:
-    case 0407:
-    case 0410:
-    case 0411:
-    case 0413:
-    case 0177545:
-       printf("\n******** %s: Not a text file ********\n\n", fs);
-       fclose (f);
-       return (NULL);
-    default:
-       break;
-    }
-    if (c == '\f')
-       *clearfirst = 1;
-    else {
-       *clearfirst = 0;
+       if (stat (fs, &stbuf) == -1) {
+               (void)fflush(stdout);
+               if (clreol)
+                       cleareol ();
+               perror(fs);
+               return((FILE *)NULL);
+       }
+       if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
+               printf("\n*** %s: directory ***\n\n", fs);
+               return((FILE *)NULL);
+       }
+       if ((f = Fopen(fs, "r")) == NULL) {
+               (void)fflush(stdout);
+               perror(fs);
+               return((FILE *)NULL);
+       }
+       if (magic(f, fs))
+               return((FILE *)NULL);
+       c = Getc(f);
+       *clearfirst = c == '\f';
        Ungetc (c, f);
        Ungetc (c, f);
-    }
-    if ((file_size = stbuf.st_size) == 0)
-       file_size = 0x7fffffffffffffffL;
-    return (f);
+       if ((file_size = stbuf.st_size) == 0)
+               file_size = LONG_MAX;
+       return(f);
+}
+
+/*
+ * magic --
+ *     check for file magic numbers.  This code would best be shared with
+ *     the file(1) program or, perhaps, more should not try and be so smart?
+ */
+static
+magic(f, fs)
+       FILE *f;
+       char *fs;
+{
+       struct exec ex;
+
+       if (fread(&ex, sizeof(ex), 1, f) == 1)
+               switch(ex.a_magic) {
+               case OMAGIC:
+               case NMAGIC:
+               case ZMAGIC:
+               case 0405:
+               case 0411:
+               case 0177545:
+                       printf("\n******** %s: Not a text file ********\n\n", fs);
+                       (void)fclose(f);
+                       return(1);
+               }
+       (void)fseek(f, 0L, L_SET);              /* rewind() not necessary */
+       return(0);
 }
 
 /*
 }
 
 /*
@@ -393,11 +456,15 @@ register int num_lines;
             *  cleareol();     /* must clear again in case we wrapped *
             */
            if (nchars < Mcol || !fold_opt)
             *  cleareol();     /* must clear again in case we wrapped *
             */
            if (nchars < Mcol || !fold_opt)
-               putchar('\n');
+               prbuf("\n", 1); /* will turn off UL if necessary */
            if (nchars == STOP)
                break;
            num_lines--;
        }
            if (nchars == STOP)
                break;
            num_lines--;
        }
+       if (pstate) {
+               tputs(ULexit, 1, putch);
+               pstate = 0;
+       }
        fflush(stdout);
        if ((c = Getc(f)) == EOF)
        {
        fflush(stdout);
        if ((c = Getc(f)) == EOF)
        {
@@ -415,8 +482,8 @@ register int num_lines;
            return;
        if (hard && promptlen > 0)
                erase (0);
            return;
        if (hard && promptlen > 0)
                erase (0);
-       if (noscroll && num_lines == dlines)
-       { 
+       if (noscroll && num_lines >= dlines)
+       {
            if (clreol)
                home();
            else
            if (clreol)
                home();
            else
@@ -451,6 +518,29 @@ onquit()
     signal(SIGQUIT, onquit);
 }
 
     signal(SIGQUIT, onquit);
 }
 
+/*
+** Come here if a signal for a window size change is received
+*/
+
+chgwinsz()
+{
+    struct winsize win;
+
+    (void) signal(SIGWINCH, SIG_IGN);
+    if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) {
+       if (win.ws_row != 0) {
+           Lpp = win.ws_row;
+           nscroll = Lpp/2 - 1;
+           if (nscroll <= 0)
+               nscroll = 1;
+           dlines = Lpp - (noscroll ? 1 : 2);
+       }
+       if (win.ws_col != 0)
+           Mcol = win.ws_col;
+    }
+    (void) signal(SIGWINCH, chgwinsz);
+}
+
 /*
 ** Clean up terminal state and exit. Also come here if interrupt signal received
 */
 /*
 ** Clean up terminal state and exit. Also come here if interrupt signal received
 */
@@ -484,16 +574,16 @@ register FILE *f;
 
 /* Simplified printf function */
 
 
 /* Simplified printf function */
 
-printf (fmt, args)
+printf (fmt, va_alist)
 register char *fmt;
 register char *fmt;
-int args;
+va_dcl
 {
 {
-       register int *argp;
+       va_list ap;
        register char ch;
        register int ccount;
 
        ccount = 0;
        register char ch;
        register int ccount;
 
        ccount = 0;
-       argp = &args;
+       va_start(ap);
        while (*fmt) {
                while ((ch = *fmt++) != '%') {
                        if (ch == '\0')
        while (*fmt) {
                while ((ch = *fmt++) != '%') {
                        if (ch == '\0')
@@ -503,14 +593,13 @@ int args;
                }
                switch (*fmt++) {
                case 'd':
                }
                switch (*fmt++) {
                case 'd':
-                       ccount += printd (*argp);
+                       ccount += printd (va_arg(ap, int));
                        break;
                case 's':
                        break;
                case 's':
-                       ccount += pr ((char *)*argp);
+                       ccount += pr (va_arg(ap, char *));
                        break;
                case '%':
                        ccount++;
                        break;
                case '%':
                        ccount++;
-                       argp--;
                        putchar ('%');
                        break;
                case '0':
                        putchar ('%');
                        break;
                case '0':
@@ -518,8 +607,8 @@ int args;
                default:
                        break;
                }
                default:
                        break;
                }
-               ++argp;
        }
        }
+       va_end(ap);
        return (ccount);
 
 }
        return (ccount);
 
 }
@@ -550,20 +639,20 @@ int n;
 char *str;
 {
     sptr = str;
 char *str;
 {
     sptr = str;
-    sprintf (n);
+    Sprintf (n);
     *sptr = '\0';
 }
 
     *sptr = '\0';
 }
 
-sprintf (n)
+Sprintf (n)
 {
     int a;
 
     if (a = n/10)
 {
     int a;
 
     if (a = n/10)
-       sprintf (a);
+       Sprintf (a);
     *sptr++ = n % 10 + '0';
 }
 
     *sptr++ = n % 10 + '0';
 }
 
-static char bell = ctrl(G);
+static char bell = ctrl('G');
 
 strlen (s)
 char *s;
 
 strlen (s)
 char *s;
@@ -606,8 +695,10 @@ char *filename;
        kill_line ();
     if (!hard) {
        promptlen = 8;
        kill_line ();
     if (!hard) {
        promptlen = 8;
-       if (Senter && Sexit)
+       if (Senter && Sexit) {
            tputs (Senter, 1, putch);
            tputs (Senter, 1, putch);
+           promptlen += (2 * soglitch);
+       }
        if (clreol)
            cleareol ();
        pr("--More--");
        if (clreol)
            cleareol ();
        pr("--More--");
@@ -618,7 +709,7 @@ char *filename;
            promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size));
        }
        if (dum_opt) {
            promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size));
        }
        if (dum_opt) {
-           promptlen += pr("[Hit space to continue, Rubout to abort]");
+           promptlen += pr("[Press space to continue, 'q' to quit.]");
        }
        if (Senter && Sexit)
            tputs (Sexit, 1, putch);
        }
        if (Senter && Sexit)
            tputs (Sexit, 1, putch);
@@ -667,15 +758,17 @@ int *length;
        }
        *p++ = c;
        if (c == '\t')
        }
        *p++ = c;
        if (c == '\t')
-           if (hardtabs && column < promptlen && !hard) {
-               if (eraseln && !dumb) {
+           if (!hardtabs || column < promptlen && !hard) {
+               if (hardtabs && eraseln && !dumb) {
                    column = 1 + (column | 7);
                    tputs (eraseln, 1, putch);
                    promptlen = 0;
                }
                else {
                    column = 1 + (column | 7);
                    tputs (eraseln, 1, putch);
                    promptlen = 0;
                }
                else {
-                   for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) {
+                   for (--p; p < &Line[LINSIZ - 1];) {
                        *p++ = ' ';
                        *p++ = ' ';
+                       if ((++column & 7) == 0)
+                           break;
                    }
                    if (column >= promptlen) promptlen = 0;
                }
                    }
                    if (column >= promptlen) promptlen = 0;
                }
@@ -707,6 +800,9 @@ int *length;
        }
     }
     colflg = column == Mcol && fold_opt;
        }
     }
     colflg = column == Mcol && fold_opt;
+    if (colflg && eatnl && Wrap) {
+       *p++ = '\n'; /* simulate normal wrap */
+    }
     *length = p - Line;
     *p = 0;
     return (column);
     *length = p - Line;
     *p = 0;
     return (column);
@@ -782,36 +878,37 @@ prbuf (s, n)
 register char *s;
 register int n;
 {
 register char *s;
 register int n;
 {
-    char c;                            /* next ouput character */
+    register char c;                   /* next output character */
     register int state;                        /* next output char's UL state */
     register int state;                        /* next output char's UL state */
-    static int pstate = 0;             /* current terminal UL state (off) */
+#define wouldul(s,n)   ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_')))
 
     while (--n >= 0)
        if (!ul_opt)
            putchar (*s++);
        else {
 
     while (--n >= 0)
        if (!ul_opt)
            putchar (*s++);
        else {
-           if (n >= 2 && s[0] == '_' && s[1] == '\b') {
-               n -= 2;
-               s += 2;
-               c = *s++;
-               state = 1;
-           } else if (n >= 2 && s[1] == '\b' && s[2] == '_') {
+           if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) {
+               s++;
+               continue;
+           }
+           if (state = wouldul(s, n)) {
+               c = (*s == '_')? s[2] : *s ;
                n -= 2;
                n -= 2;
+               s += 3;
+           } else
                c = *s++;
                c = *s++;
-               s += 2;
-               state = 1;
-           } else {
-               c = *s++;
-               state = 0;
+           if (state != pstate) {
+               if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1))
+                   state = 1;
+               else
+                   tputs(state ? ULenter : ULexit, 1, putch);
            }
            }
-           if (state != pstate)
-               tputs(state ? ULenter : ULexit, 1, putch);
-           pstate = state;
-           putchar(c);
+           if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0)
+               putchar(c);
            if (state && *chUL) {
                pr(chBS);
                tputs(chUL, 1, putch);
            }
            if (state && *chUL) {
                pr(chBS);
                tputs(chUL, 1, putch);
            }
+           pstate = state;
        }
 }
 
        }
 }
 
@@ -872,7 +969,7 @@ register FILE *f;
        errors = 0;
     if (MBIT == RAW && slow_tty) {
        otty.sg_flags |= MBIT;
        errors = 0;
     if (MBIT == RAW && slow_tty) {
        otty.sg_flags |= MBIT;
-       stty(2, &otty);
+       stty(fileno(stderr), &otty);
     }
     for (;;) {
        nlines = number (&comchar);
     }
     for (;;) {
        nlines = number (&comchar);
@@ -897,16 +994,56 @@ register FILE *f;
            if (retval >= 0)
                done++;
            break;
            if (retval >= 0)
                done++;
            break;
+       case 'b':
+       case ctrl('B'):
+           {
+               register int initline;
+
+               if (no_intty) {
+                   write(2, &bell, 1);
+                   return (-1);
+               }
+
+               if (nlines == 0) nlines++;
+
+               putchar ('\r');
+               erase (0);
+               printf ("\n");
+               if (clreol)
+                       cleareol ();
+               printf ("...back %d page", nlines);
+               if (nlines > 1)
+                       pr ("s\n");
+               else
+                       pr ("\n");
+
+               if (clreol)
+                       cleareol ();
+               pr ("\n");
+
+               initline = Currline - dlines * (nlines + 1);
+               if (! noscroll)
+                   --initline;
+               if (initline < 0) initline = 0;
+               Fseek(f, 0L);
+               Currline = 0;   /* skiplns() will make Currline correct */
+               skiplns(initline, f);
+               if (! noscroll) {
+                   ret(dlines + 1);
+               }
+               else {
+                   ret(dlines);
+               }
+           }
        case ' ':
        case 'z':
            if (nlines == 0) nlines = dlines;
            else if (comchar == 'z') dlines = nlines;
            ret (nlines);
        case 'd':
        case ' ':
        case 'z':
            if (nlines == 0) nlines = dlines;
            else if (comchar == 'z') dlines = nlines;
            ret (nlines);
        case 'd':
-       case ctrl(D):
+       case ctrl('D'):
            if (nlines != 0) nscroll = nlines;
            ret (nscroll);
            if (nlines != 0) nscroll = nlines;
            ret (nscroll);
-       case RUBOUT:
        case 'q':
        case 'Q':
            end_it ();
        case 'q':
        case 'Q':
            end_it ();
@@ -996,25 +1133,39 @@ register FILE *f;
        case '!':
            do_shell (filename);
            break;
        case '!':
            do_shell (filename);
            break;
+       case '?':
        case 'h':
            if ((helpf = fopen (HELPFILE, "r")) == NULL)
                error ("Can't open help file");
            if (noscroll) doclear ();
            copy_file (helpf);
        case 'h':
            if ((helpf = fopen (HELPFILE, "r")) == NULL)
                error ("Can't open help file");
            if (noscroll) doclear ();
            copy_file (helpf);
-           close (helpf);
+           fclose (helpf);
            prompt (filename);
            break;
        case 'v':       /* This case should go right before default */
            if (!no_intty) {
                kill_line ();
                cmdbuf[0] = '+';
            prompt (filename);
            break;
        case 'v':       /* This case should go right before default */
            if (!no_intty) {
                kill_line ();
                cmdbuf[0] = '+';
-               scanstr (Currline, &cmdbuf[1]);
+               scanstr (Currline - dlines < 0 ? 0
+                               : Currline - (dlines + 1) / 2, &cmdbuf[1]);
                pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]);
                execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0);
                break;
            }
        default:
                pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]);
                execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0);
                break;
            }
        default:
-           write (2, &bell, 1);
+           if (dum_opt) {
+               kill_line ();
+               if (Senter && Sexit) {
+                   tputs (Senter, 1, putch);
+                   promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch);
+                   tputs (Sexit, 1, putch);
+               }
+               else
+                   promptlen = pr ("[Press 'h' for instructions.]");
+               fflush (stdout);
+           }
+           else
+               write (2, &bell, 1);
            break;
        }
        if (done) break;
            break;
        }
        if (done) break;
@@ -1025,7 +1176,7 @@ endsw:
     notell++;
     if (MBIT == RAW && slow_tty) {
        otty.sg_flags &= ~MBIT;
     notell++;
     if (MBIT == RAW && slow_tty) {
        otty.sg_flags &= ~MBIT;
-       stty(2, &otty);
+       stty(fileno(stderr), &otty);
     }
     return (retval);
 }
     }
     return (retval);
 }
@@ -1184,7 +1335,7 @@ register int n;
                            if (clreol) {
                                home ();
                                cleareol ();
                            if (clreol) {
                                home ();
                                cleareol ();
-                           } 
+                           }
                            else
                                doclear ();
                    }
                            else
                                doclear ();
                    }
@@ -1192,9 +1343,9 @@ register int n;
                        kill_line ();
                        if (noscroll)
                            if (clreol) {
                        kill_line ();
                        if (noscroll)
                            if (clreol) {
-                               home (); 
+                               home ();
                                cleareol ();
                                cleareol ();
-                           } 
+                           }
                            else
                                doclear ();
                        pr (Line);
                            else
                                doclear ();
                        pr (Line);
@@ -1219,30 +1370,43 @@ register int n;
     }
 }
 
     }
 }
 
-execute (filename, cmd, args)
+/*VARARGS2*/
+execute (filename, cmd, va_alist)
 char *filename;
 char *filename;
-char *cmd, *args;
+char *cmd;
+va_dcl
 {
        int id;
 {
        int id;
+       int n;
+       va_list argp;
 
        fflush (stdout);
        reset_tty ();
 
        fflush (stdout);
        reset_tty ();
-       while ((id = fork ()) < 0)
+       for (n = 10; (id = fork ()) < 0 && n > 0; n--)
            sleep (5);
        if (id == 0) {
            sleep (5);
        if (id == 0) {
-           execv (cmd, &args);
+           if (!isatty(0)) {
+               close(0);
+               open("/dev/tty", 0);
+           }
+           va_start(argp);
+           execv (cmd, argp);
            write (2, "exec failed\n", 12);
            exit (1);
            write (2, "exec failed\n", 12);
            exit (1);
+           va_end(argp);       /* balance {}'s for some UNIX's */
        }
        }
-       signal (SIGINT, SIG_IGN);
-       signal (SIGQUIT, SIG_IGN);
-       if (catch_susp)
-           signal(SIGTSTP, SIG_DFL);
-       wait (0);
-       signal (SIGINT, end_it);
-       signal (SIGQUIT, onquit);
-       if (catch_susp)
-           signal(SIGTSTP, onsusp);
+       if (id > 0) {
+           signal (SIGINT, SIG_IGN);
+           signal (SIGQUIT, SIG_IGN);
+           if (catch_susp)
+               signal(SIGTSTP, SIG_DFL);
+           while (wait(0) > 0);
+           signal (SIGINT, end_it);
+           signal (SIGQUIT, onquit);
+           if (catch_susp)
+               signal(SIGTSTP, onsusp);
+       } else
+           write(2, "can't fork\n", 11);
        set_tty ();
        pr ("------------------------\n");
        prompt (filename);
        set_tty ();
        pr ("------------------------\n");
        prompt (filename);
@@ -1303,25 +1467,58 @@ register int nskip;
 initterm ()
 {
     char       buf[TBUFSIZ];
 initterm ()
 {
     char       buf[TBUFSIZ];
-    char       clearbuf[100];
+    static char        clearbuf[TBUFSIZ];
     char       *clearptr, *padstr;
     int                ldisc;
     char       *clearptr, *padstr;
     int                ldisc;
+    int                lmode;
     char       *term;
     char       *term;
-
-    setbuf(stdout, obuf);
-    if (!(no_tty = gtty(1, &otty))) {
-       if ((term = getenv("TERM")) || tgetent(buf, term) <= 0) {
+    int                tgrp;
+    struct winsize win;
+
+retry:
+    if (!(no_tty = gtty(fileno(stdout), &otty))) {
+       if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) {
+           perror("TIOCLGET");
+           exit(1);
+       }
+       docrterase = ((lmode & LCRTERA) != 0);
+       docrtkill = ((lmode & LCRTKIL) != 0);
+       /*
+        * Wait until we're in the foreground before we save the
+        * the terminal modes.
+        */
+       if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) {
+           perror("TIOCGPGRP");
+           exit(1);
+       }
+       if (tgrp != getpgrp(0)) {
+           kill(0, SIGTTOU);
+           goto retry;
+       }
+       if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) {
            dumb++; ul_opt = 0;
        }
        else {
            dumb++; ul_opt = 0;
        }
        else {
-           if (((Lpp = tgetnum("li")) < 0) || tgetflag("hc")) {
+           if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) {
+               Lpp = tgetnum("li");
+               Mcol = tgetnum("co");
+           } else {
+               if ((Lpp = win.ws_row) == 0)
+                   Lpp = tgetnum("li");
+               if ((Mcol = win.ws_col) == 0)
+                   Mcol = tgetnum("co");
+           }
+           if ((Lpp <= 0) || tgetflag("hc")) {
                hard++; /* Hard copy terminal */
                Lpp = 24;
            }
                hard++; /* Hard copy terminal */
                Lpp = 24;
            }
+           if (tgetflag("xn"))
+               eatnl++; /* Eat newline at last column + 1; dec, concept */
+           if (Mcol <= 0)
+               Mcol = 80;
+
            if (tailequ (fnames[0], "page") || !hard && tgetflag("ns"))
                noscroll++;
            if (tailequ (fnames[0], "page") || !hard && tgetflag("ns"))
                noscroll++;
-           if ((Mcol = tgetnum("co")) < 0)
-               Mcol = 80;
            Wrap = tgetflag("am");
            bad_so = tgetflag ("xs");
            clearptr = clearbuf;
            Wrap = tgetflag("am");
            bad_so = tgetflag ("xs");
            clearptr = clearbuf;
@@ -1329,6 +1526,8 @@ initterm ()
            Clear = tgetstr("cl", &clearptr);
            Senter = tgetstr("so", &clearptr);
            Sexit = tgetstr("se", &clearptr);
            Clear = tgetstr("cl", &clearptr);
            Senter = tgetstr("so", &clearptr);
            Sexit = tgetstr("se", &clearptr);
+           if ((soglitch = tgetnum("sg")) < 0)
+               soglitch = 0;
 
            /*
             *  Set up for underlining:  some terminals don't need it;
 
            /*
             *  Set up for underlining:  some terminals don't need it;
@@ -1342,13 +1541,18 @@ initterm ()
                ul_opt = 0;
            if ((chUL = tgetstr("uc", &clearptr)) == NULL )
                chUL = "";
                ul_opt = 0;
            if ((chUL = tgetstr("uc", &clearptr)) == NULL )
                chUL = "";
-           if ((ULenter = tgetstr("us", &clearptr)) == NULL &&
-               (!*chUL) && (ULenter = tgetstr("so", &clearptr)) == NULL)
-               ULenter = "";
-           if ((ULexit = tgetstr("ue", &clearptr)) == NULL &&
-               (!*chUL) && (ULexit = tgetstr("se", &clearptr)) == NULL)
-               ULexit = "";
-           
+           if (((ULenter = tgetstr("us", &clearptr)) == NULL ||
+                (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) {
+               if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) {
+                       ULenter = "";
+                       ULexit = "";
+               } else
+                       ulglitch = soglitch;
+           } else {
+               if ((ulglitch = tgetnum("ug")) < 0)
+                   ulglitch = 0;
+           }
+
            if (padstr = tgetstr("pc", &clearptr))
                PC = *padstr;
            Home = tgetstr("ho",&clearptr);
            if (padstr = tgetstr("pc", &clearptr))
                PC = *padstr;
            Home = tgetstr("ho",&clearptr);
@@ -1360,15 +1564,19 @@ initterm ()
               }
            }
            EodClr = tgetstr("cd", &clearptr);
               }
            }
            EodClr = tgetstr("cd", &clearptr);
+           if ((chBS = tgetstr("bc", &clearptr)) == NULL)
+               chBS = "\b";
+
        }
        if ((shell = getenv("SHELL")) == NULL)
            shell = "/bin/sh";
     }
        }
        if ((shell = getenv("SHELL")) == NULL)
            shell = "/bin/sh";
     }
-    no_intty = gtty(0, &otty);
-    gtty(2, &otty);
+    no_intty = gtty(fileno(stdin), &otty);
+    gtty(fileno(stderr), &otty);
+    savetty = otty;
     ospeed = otty.sg_ospeed;
     slow_tty = ospeed < B1200;
     ospeed = otty.sg_ospeed;
     slow_tty = ospeed < B1200;
-    hardtabs =  !(otty.sg_flags & XTABS);
+    hardtabs = (otty.sg_flags & TBDELAY) != XTABS;
     if (!no_tty) {
        otty.sg_flags &= ~ECHO;
        if (MBIT == CBREAK || !slow_tty)
     if (!no_tty) {
        otty.sg_flags &= ~ECHO;
        if (MBIT == CBREAK || !slow_tty)
@@ -1381,16 +1589,23 @@ readch ()
        char ch;
        extern int errno;
 
        char ch;
        extern int errno;
 
+       errno = 0;
        if (read (2, &ch, 1) <= 0)
                if (errno != EINTR)
        if (read (2, &ch, 1) <= 0)
                if (errno != EINTR)
-                       exit(0);
+                       end_it();
                else
                        ch = otty.sg_kill;
        return (ch);
 }
 
 static char BS = '\b';
                else
                        ch = otty.sg_kill;
        return (ch);
 }
 
 static char BS = '\b';
+static char *BSB = "\b \b";
 static char CARAT = '^';
 static char CARAT = '^';
+#define ERASEONECHAR \
+    if (docrterase) \
+       write (2, BSB, sizeof(BSB)); \
+    else \
+       write (2, &BS, sizeof(BS));
 
 ttyin (buf, nmax, pchar)
 char buf[];
 
 ttyin (buf, nmax, pchar)
 char buf[];
@@ -1414,11 +1629,11 @@ char pchar;
        else if ((ch == otty.sg_erase) && !slash) {
            if (sptr > buf) {
                --promptlen;
        else if ((ch == otty.sg_erase) && !slash) {
            if (sptr > buf) {
                --promptlen;
-               write (2, &BS, 1);
+               ERASEONECHAR
                --sptr;
                if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) {
                    --promptlen;
                --sptr;
                if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) {
                    --promptlen;
-                   write (2, &BS, 1);
+                   ERASEONECHAR
                }
                continue;
            }
                }
                continue;
            }
@@ -1438,6 +1653,9 @@ char pchar;
                putchar (pchar);
                if (eraseln)
                    erase (1);
                putchar (pchar);
                if (eraseln)
                    erase (1);
+               else if (docrtkill)
+                   while (promptlen-- > 1)
+                       write (2, BSB, sizeof(BSB));
                promptlen = 1;
            }
            sptr = buf;
                promptlen = 1;
            }
            sptr = buf;
@@ -1445,7 +1663,7 @@ char pchar;
            continue;
        }
        if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) {
            continue;
        }
        if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) {
-           write (2, &BS, 1);
+           ERASEONECHAR
            --sptr;
        }
        if (ch != '\\')
            --sptr;
        }
        if (ch != '\\')
@@ -1553,14 +1771,21 @@ set_tty ()
 {
        otty.sg_flags |= MBIT;
        otty.sg_flags &= ~ECHO;
 {
        otty.sg_flags |= MBIT;
        otty.sg_flags &= ~ECHO;
-       stty(2, &otty);
+       stty(fileno(stderr), &otty);
 }
 
 reset_tty ()
 {
 }
 
 reset_tty ()
 {
+    if (no_tty)
+       return;
+    if (pstate) {
+       tputs(ULexit, 1, putch);
+       fflush(stdout);
+       pstate = 0;
+    }
     otty.sg_flags |= ECHO;
     otty.sg_flags &= ~MBIT;
     otty.sg_flags |= ECHO;
     otty.sg_flags &= ~MBIT;
-    stty(2, &otty);
+    stty(fileno(stderr), &savetty);
 }
 
 rdline (f)
 }
 
 rdline (f)
@@ -1581,9 +1806,14 @@ register FILE *f;
 
 onsusp ()
 {
 
 onsusp ()
 {
+    /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
+    signal(SIGTTOU, SIG_IGN);
     reset_tty ();
     fflush (stdout);
     reset_tty ();
     fflush (stdout);
+    signal(SIGTTOU, SIG_DFL);
     /* Send the TSTP signal to suspend our process group */
     /* Send the TSTP signal to suspend our process group */
+    signal(SIGTSTP, SIG_DFL);
+    sigsetmask(0);
     kill (0, SIGTSTP);
     /* Pause for station break */
 
     kill (0, SIGTSTP);
     /* Pause for station break */