modern syntax for asgops & inits cause Donn's latest ccom rejects the old.
[unix-history] / usr / src / old / more / more.c
index d4eb516..0d410a2 100644 (file)
@@ -1,4 +1,18 @@
-static char *sccsid = "@(#)more.c      4.11 (Berkeley) 83/03/17";
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#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.7 (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 +24,18 @@ static      char *sccsid = "@(#)more.c      4.11 (Berkeley) 83/03/17";
 */
 
 #include <stdio.h>
 */
 
 #include <stdio.h>
+#include <sys/types.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 <sys/exec.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
@@ -40,10 +53,10 @@ static      char *sccsid = "@(#)more.c      4.11 (Berkeley) 83/03/17";
 #define ESC    '\033'
 #define QUIT   '\034'
 
 #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 +68,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 +82,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 +97,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 +118,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 +129,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,11 +160,12 @@ 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 (dlines == 0)
        dlines = Lpp - (noscroll ? 1 : 2);
     left = dlines;
@@ -161,11 +182,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)
@@ -329,23 +351,13 @@ int *clearfirst;
        perror(fs);
        return (NULL);
     }
        perror(fs);
        return (NULL);
     }
-    c = Getc(f);
-
     /* Try to see whether it is an ASCII file */
     /* 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:
+    if (magic(f)) {
        printf("\n******** %s: Not a text file ********\n\n", fs);
        fclose (f);
        return (NULL);
        printf("\n******** %s: Not a text file ********\n\n", fs);
        fclose (f);
        return (NULL);
-    default:
-       break;
     }
     }
+    c = Getc(f);
     if (c == '\f')
        *clearfirst = 1;
     else {
     if (c == '\f')
        *clearfirst = 1;
     else {
@@ -357,6 +369,22 @@ int *clearfirst;
     return (f);
 }
 
     return (f);
 }
 
+/*
+ * 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?
+ */
+magic(f)
+    FILE *f;
+{
+    long magic;
+
+    magic = getw(f);
+    fseek(f, -sizeof (magic), L_INCR);         /* reset file position */
+    return (magic == 0405 || magic == OMAGIC || magic == NMAGIC ||
+       magic == 0411 || magic == ZMAGIC || magic == 0177545);
+}
+
 /*
 ** A real function, for the tputs routine in termlib
 */
 /*
 ** A real function, for the tputs routine in termlib
 */
@@ -409,11 +437,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)
        {
@@ -432,7 +464,7 @@ register int num_lines;
        if (hard && promptlen > 0)
                erase (0);
        if (noscroll && num_lines >= dlines)
        if (hard && promptlen > 0)
                erase (0);
        if (noscroll && num_lines >= dlines)
-       { 
+       {
            if (clreol)
                home();
            else
            if (clreol)
                home();
            else
@@ -467,6 +499,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
 */
@@ -622,8 +677,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--");
@@ -634,7 +691,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);
@@ -683,15 +740,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;
                }
@@ -723,6 +782,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);
@@ -798,36 +860,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;
        }
 }
 
        }
 }
 
@@ -888,7 +951,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);
@@ -913,6 +976,47 @@ 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;
        case ' ':
        case 'z':
            if (nlines == 0) nlines = dlines;
@@ -922,7 +1026,6 @@ register FILE *f;
        case ctrl(D):
            if (nlines != 0) nscroll = nlines;
            ret (nscroll);
        case ctrl(D):
            if (nlines != 0) nscroll = nlines;
            ret (nscroll);
-       case RUBOUT:
        case 'q':
        case 'Q':
            end_it ();
        case 'q':
        case 'Q':
            end_it ();
@@ -1012,25 +1115,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;
@@ -1041,7 +1158,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);
 }
@@ -1200,7 +1317,7 @@ register int n;
                            if (clreol) {
                                home ();
                                cleareol ();
                            if (clreol) {
                                home ();
                                cleareol ();
-                           } 
+                           }
                            else
                                doclear ();
                    }
                            else
                                doclear ();
                    }
@@ -1208,9 +1325,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);
@@ -1240,25 +1357,33 @@ char *filename;
 char *cmd, *args;
 {
        int id;
 char *cmd, *args;
 {
        int id;
+       int n;
 
        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) {
+           if (!isatty(0)) {
+               close(0);
+               open("/dev/tty", 0);
+           }
            execv (cmd, &args);
            write (2, "exec failed\n", 12);
            exit (1);
        }
            execv (cmd, &args);
            write (2, "exec failed\n", 12);
            exit (1);
        }
-       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);
@@ -1319,25 +1444,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;
@@ -1345,6 +1503,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;
@@ -1358,17 +1518,22 @@ 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);
-           if (Home == 0 && *Home == '\0')
+           if (Home == 0 || *Home == '\0')
            {
                if ((cursorm = tgetstr("cm", &clearptr)) != NULL) {
                    strcpy(cursorhome, tgoto(cursorm, 0, 0));
            {
                if ((cursorm = tgetstr("cm", &clearptr)) != NULL) {
                    strcpy(cursorhome, tgoto(cursorm, 0, 0));
@@ -1376,15 +1541,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)
@@ -1406,7 +1575,13 @@ readch ()
 }
 
 static char BS = '\b';
 }
 
 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[];
@@ -1430,11 +1605,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;
            }
@@ -1454,6 +1629,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;
@@ -1461,7 +1639,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 != '\\')
@@ -1569,14 +1747,19 @@ 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 (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)
@@ -1597,9 +1780,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 */