xref: /titanic_51/usr/src/cmd/more/more.c (revision bfa62c284402a2e7ee6a349df0ef8d1aa2e908e8)
1  /*
2   * CDDL HEADER START
3   *
4   * The contents of this file are subject to the terms of the
5   * Common Development and Distribution License (the "License").
6   * You may not use this file except in compliance with the License.
7   *
8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9   * or http://www.opensolaris.org/os/licensing.
10   * See the License for the specific language governing permissions
11   * and limitations under the License.
12   *
13   * When distributing Covered Code, include this CDDL HEADER in each
14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15   * If applicable, add the following below this CDDL HEADER, with the
16   * fields enclosed by brackets "[]" replaced with your own identifying
17   * information: Portions Copyright [yyyy] [name of copyright owner]
18   *
19   * CDDL HEADER END
20   */
21  /*
22   * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23   * Use is subject to license terms.
24   */
25  
26  /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27  /*	  All Rights Reserved  	*/
28  
29  /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
30  /*	  All Rights Reserved	*/
31  
32  /*
33   * University Copyright- Copyright (c) 1982, 1986, 1988
34   * The Regents of the University of California
35   * All Rights Reserved
36   *
37   * University Acknowledgment- Portions of this document are derived from
38   * software developed by the University of California, Berkeley, and its
39   * contributors.
40   */
41  
42  #pragma ident	"%Z%%M%	%I%	%E% SMI"
43  
44  /*
45   *      @(#) more.c 1.1 88/03/29 more:more.c
46   */
47  
48  /*
49  ** more.c - General purpose tty output filter and file perusal program
50  **
51  **      by Eric Shienbrood, UC Berkeley
52  **
53  **      modified by Geoff Peck, UCB to add underlining, single spacing
54  **      modified by John Foderaro, UCB to add -c and MORE environment variable
55  **      modified by Hans Spiller, Microsoft to handle \r better July 23, 82
56  **              added ? help command, and -w
57  **
58  **      vwh     11 Jan 83       M001
59  **              modified to handle x.out magic number and magic number
60  **              byte ordering OTHER than the vax and pdp11.
61  **      JJD     19 Jan 83       M002
62  **              - fix distributed on USENET
63  **                From decvax!ucbvax!dist2 Sun Dec  6 02:58:31 1981
64  **                Subject: FIXED:  bug in src/more/more.c
65  **              - fixed bug on terminal with "magic cookie" standout
66  **                sequences.
67  **      JJD     14 Feb 83       M003
68  **              - fix exit status of more
69  **              - Made first letter of "no more" message uppercase
70  **      andyp   03 Aug 83       M004    3.0 upgrade
71  **      - moved <local/uparm.h> to cmd/include.
72  **      - use UCB, rather than XENIX, stty(2).
73  **      andyp   30 Nov 83       M005
74  **      - (thanks to reubenb).  Changed frame variable to static, it is
75  **        used as a global buffer.  We never saw the bug before because
76  **        of the depth of the stack.
77  **      barrys  03 Jul 84       M006
78  **      - Updated the usage message to include the 's' and 'w' options
79  **        and to make the 'n' option a separate entry (uncommented).
80  **      ericc   26 Dec 84       M007
81  **      - Replaced the constant 0x7fffffffffffffffL with MAXLONG.
82  **      ericc   25 Jul 85       M008
83  **      - made "-r" option display control characters as '^x', as documented.
84  **      - fixed processing of '\b' so that more doesn't terminate when
85  **        the sequence "\b\n" is encountered.
86  **      - changed "Hit Rubout ..." to "Hit Del ...", for ibm keyboards.
87  **	davidby 9 March 1988	Unmarked
88  **	- replaced all locally defined functions with library equivalents,
89  **	- changed from termcap to terminfo
90  **	- included <values.h> for MAXLONG value
91  **	- removed most ifdef code for V6, V7, and BSD
92  **	- added /etc/magic support for file type checking
93  */
94  
95  #include <ctype.h>
96  #include <signal.h>
97  #include <errno.h>
98  #include <sys/types.h>
99  #include <sys/wait.h>
100  #include <curses.h>
101  #include <term.h>
102  #include <sys/ioctl.h>
103  #include <setjmp.h>
104  #include <sys/stat.h>
105  #include <values.h>
106  #include <stdlib.h>
107  #include <stdarg.h>
108  #include <string.h>
109  #include <unistd.h>
110  #include <libgen.h>
111  #include <euc.h>
112  #include <getwidth.h>
113  #include <locale.h>
114  #include <widec.h>
115  #include <wctype.h>
116  #include <limits.h>
117  eucwidth_t wp;
118  int     cw[4];
119  int     scw[4];
120  #include <locale.h>
121  
122  /* Help file will eventually go in libpath(more.help) on all systems */
123  
124  #ifdef INGRES
125  #define VI              "/usr/bin/vi"
126  #define HELPFILE        "/mntp/doucette/more/more.help"
127  #define LOCAL_HELP	"/usr/lib/locale/%s/LC_MESSAGES/more.help"
128  #endif
129  
130  #ifndef INGRES
131  #ifndef HELPFILE
132  #define HELPFILE        "/usr/lib/more.help"
133  #define LOCAL_HELP	"/usr/lib/locale/%s/LC_MESSAGES/more.help"
134  #endif
135  #define VI              "vi"
136  #endif
137  
138  #define Fopen(s,m)      (Currline = 0,file_pos=0,fopen(s,m))
139  #define Ftell(f)        file_pos
140  #define Fseek(f,off)    (file_pos=off,fseeko(f,off,0))
141  #define Getc(f)         (++file_pos, getc(f))
142  #define Ungetc(c,f)     (--file_pos, ungetc(c,f))
143  
144  #define pr(s1)		fputs(s1, stdout)
145  #define clreos()	putp(clr_eos)
146  #define cleareol()	putp(clr_eol)
147  #define home()		putp(cursor_home)
148  
149  #define LINSIZ  512
150  #define ctrl(letter)    ((letter) & 077)
151  #define RUBOUT  '\177'
152  #define ESC     '\033'
153  #define QUIT    '\034'
154  
155  struct termio   otty;           /* old tty modes */
156  struct termio   ntty;           /* new tty modes */
157  off_t           file_pos, file_size;
158  int             fnum, no_intty, no_tty;
159  int             dum_opt;
160  off_t           dlines;
161  void end_it(int sig);
162  void onquit(int sig);
163  void chgwinsz(int sig);
164  #ifdef SIGTSTP
165  void             onsusp(int sig);
166  #endif
167  int             nscroll = 11;   /* Number of lines scrolled by 'd' */
168  int             fold_opt = 1;   /* Fold long lines */
169  int             stop_opt = 1;   /* Stop after form feeds */
170  int             ssp_opt = 0;    /* Suppress white space */
171  int             ul_opt = 1;     /* Underline as best we can */
172  int             cr_opt = 0;     /* show ctrl characters as '^c' */
173  int             wait_opt = 0;   /* prompt for exit at eof */
174  int             promptlen;
175  off_t		Currline;       /* Line we are currently at */
176  int             startup = 1;
177  int             firstf = 1;
178  int             notell = 1;
179  int             inwait, Pause, errors;
180  int             within; /* true if we are within a file,
181                          false if we are between files */
182  int             hard, dumb, noscroll, hardtabs, clreol;
183  int             catch_susp;     /* We should catch the SIGTSTP signal */
184  char            **fnames;       /* The list of file names */
185  int             nfiles;         /* Number of files left to process */
186  char            *shell;         /* The name of the shell to use */
187  int             shellp;         /* A previous shell command exists */
188  char            ch;
189  jmp_buf         restore;
190  char            obuf[BUFSIZ];   /* stdout buffer */
191  char            Line[LINSIZ];   /* Line buffer */
192  int             Lpp = 24;       /* lines per page */
193  char            *ULenter, *ULexit;      /* enter and exit underline mode */
194  int             Mcol = 80;      /* number of columns */
195  int             Wrap = 1;       /* set if automargins */
196  int		fseeko();
197  struct {
198      off_t chrctr, line;
199  } context, screen_start;
200  int             exitstat = 0;   /* status to use when exiting more */   /*M003*/
201  
202  static void execute(char *filename, char *cmd, ...);
203  static void error(char *mess);
204  static void wait_eof(void);
205  static void prompt(char *filename);
206  static void argscan(char *s);
207  static void copy_file(register FILE *f);
208  static void initterm(void);
209  static void do_shell(char *filename);
210  static FILE *checkf(register char *fs, int *clearfirst);
211  static void screen(register FILE *f, register off_t num_lines);
212  static void skiplns(register off_t n, register FILE *f);
213  static void skipf(register int nskip);
214  static int readch(void);
215  static void prmpt_erase(register int col);
216  static void kill_line(void);
217  static void prbuf(register char *s, register int n);
218  static void search(char buf[], FILE *file, register off_t n);
219  static void doclear(void);
220  static void ttyin(char buf[], register int nmax, char pchar);
221  static int expand(char *outbuf, char *inbuf);
222  static void show(register char ch);
223  static void set_tty(void);
224  static void reset_tty(void);
225  static void rdline(register FILE *f);
226  static off_t command(char *filename, register FILE *f);
227  static int getline(register FILE *f, int *length);
228  static int number(char *cmd);
229  static int colon(char *filename, int cmd, off_t nlines);
230  
231  int
232  main(int argc, char *argv[])
233  {
234      register FILE       *f;
235      register char       *s;
236      register char       *p;
237      register int	ch;
238      register off_t      left;
239      int                 prnames = 0;
240      int                 initopt = 0;
241      int                 srchopt = 0;
242      int                 clearit = 0;
243      off_t               initline;
244      char                initbuf[80];
245  
246      setlocale( LC_ALL, "" );
247      getwidth(&wp);
248      cw[0] = 1;
249      cw[1] = wp._eucw1;
250      cw[2] = wp._eucw2+1;
251      cw[3] = wp._eucw3+1;
252      scw[0] = 1;
253      scw[1] = wp._scrw1;
254      scw[2] = wp._scrw2;
255      scw[3] = wp._scrw3;
256  
257      nfiles = argc;
258      fnames = argv;
259  
260      (void) setlocale(LC_ALL,"");
261  #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
262  #define TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
263  #endif
264  	(void) textdomain(TEXT_DOMAIN);
265  
266      initterm ();
267      if(s = getenv("MORE")) argscan(s);
268      while (--nfiles > 0) {
269          if ((ch = (*++fnames)[0]) == '-') {
270              argscan(*fnames+1);
271          }
272          else if (ch == '+') {
273              s = *fnames;
274              if (*++s == '/') {
275                  srchopt++;
276                  for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';)
277                      *p++ = *s++;
278                  *p = '\0';
279              }
280              else {
281                  initopt++;
282                  for (initline = 0; *s != '\0'; s++)
283                      if (isdigit (*s))
284                          initline = initline*10 + *s -'0';
285                  --initline;
286              }
287          }
288          else break;
289      }
290      /* allow clreol only if cursor_home and clr_eol and clr_eos strings are
291       *  defined, and in that case, make sure we are in noscroll mode
292       */
293      if(clreol)
294      {
295          if (!cursor_home || !clr_eol || !clr_eos) {
296             	clreol = 0;
297  	}
298          else noscroll = 1;
299      }
300  
301      if (dlines == 0)
302          dlines =(off_t) (Lpp - (noscroll ? 1 : 2));
303      left = dlines;
304      if (nfiles > 1)
305          prnames++;
306      if (!no_intty && nfiles == 0) {
307  	fprintf(stderr, gettext("Usage: %s\
308   [-cdflrsuw] [-lines] [+linenumber] [+/pattern] [filename ...].\n")
309  	, argv[0]);
310          exit(1);
311      }
312      else
313          f = stdin;
314      if (!no_tty) {
315          signal(SIGQUIT, onquit);
316          signal(SIGINT, end_it);
317          signal(SIGWINCH, chgwinsz);
318  #ifdef SIGTSTP
319          if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) {
320              signal(SIGTSTP, onsusp);
321              catch_susp++;
322          }
323  #endif
324          set_tty();
325      }
326      if (no_intty) {
327          if (no_tty)
328              copy_file (stdin);
329          else {
330              if ((ch = Getc (f)) == '\f')
331                  doclear();
332              else {
333                  Ungetc (ch, f);
334                  if (noscroll && (ch != EOF)) {
335                      if (clreol)
336                          home ();
337                      else
338                          doclear ();
339                  }
340              }
341              if (!setjmp(restore)) {
342                  if (srchopt) {
343                      search (initbuf, stdin,(off_t) 1);
344                      if (noscroll)
345                          left--;
346                      }
347                  else if (initopt)
348                      skiplns (initline, stdin);
349                  }
350              else
351                  left = command(NULL, f);
352              screen (stdin, left);
353          }
354          no_intty = 0;
355          prnames++;
356          firstf = 0;
357      }
358  
359      while (fnum < nfiles) {
360          if ((f = checkf (fnames[fnum], &clearit)) != NULL) {
361              context.line = context.chrctr = 0;
362              Currline = 0;
363              if (firstf) setjmp (restore);
364              if (firstf) {
365                  firstf = 0;
366                  if (srchopt)
367                  {
368                      search (initbuf, f,(off_t) 1);
369                      if (noscroll)
370                          left--;
371                  }
372                  else if (initopt)
373                      skiplns (initline, f);
374              }
375              else if (fnum < nfiles && !no_tty) {
376                  setjmp (restore);
377                  left = command (fnames[fnum], f);
378              }
379              if (left != 0) {
380                  if ((noscroll || clearit) && (file_size != LLONG_MAX))
381                      if (clreol)
382                          home ();
383                      else
384                          doclear ();
385                  if (prnames) {
386                      if (ceol_standout_glitch)
387                          prmpt_erase (0);
388                      if (clreol)
389                          cleareol ();
390                      pr("::::::::::::::");
391                      if (promptlen > 14)
392                          prmpt_erase (14);
393                      printf ("\n");
394                      if(clreol) cleareol();
395                      printf("%s\n", fnames[fnum]);
396                      if(clreol) cleareol();
397                      pr("::::::::::::::\n");
398                      if (left > (off_t)(Lpp - 4))
399                          left =(off_t)(Lpp - 4);
400                  }
401                  if (no_tty)
402                      copy_file (f);
403                  else {
404                      within++;
405                      screen(f, left);
406                      within = 0;
407                  }
408              }
409              setjmp (restore);
410              fflush(stdout);
411              fclose(f);
412              screen_start.line = screen_start.chrctr = 0LL;
413              context.line = context.chrctr = 0LL;
414          } else
415              exitstat |= 1;                      /*M003*/
416          fnum++;
417          firstf = 0;
418      }
419      if (wait_opt) wait_eof();
420      reset_tty ();
421      return (exitstat);                             /*M003*/
422  }
423  
424  static void
425  argscan(char *s)
426  {
427              for (dlines = 0; *s != '\0'; s++)
428                  if (isdigit(*s))
429                      dlines = dlines*10 + *s - '0';
430                  else if (*s == 'd')
431                      dum_opt = 1;
432                  else if (*s == 'l')
433                      stop_opt = 0;
434                  else if (*s == 'f')
435                      fold_opt = 0;
436                  else if (*s == 'p')
437                      noscroll++;
438                  else if (*s == 'c')
439                      clreol++;
440                  else if (*s == 's')
441                      ssp_opt = 1;
442                  else if (*s == 'u')
443                      ul_opt = 0;
444                  else if (*s == 'r')
445                      cr_opt = 1;
446                  else if (*s == 'w')
447                      wait_opt = 1;
448  }
449  
450  
451  /*
452  ** Check whether the file named by fs is a file which the user may
453  ** access.  If it is, return the opened file. Otherwise return NULL.
454  */
455  
456  static FILE *
457  checkf(register char *fs, int *clearfirst)
458  {
459      struct stat stbuf;
460      register FILE *f;
461      int c;
462  
463      if (stat (fs, &stbuf) == -1) {
464          fflush(stdout);
465          if (clreol)
466              cleareol ();
467          perror(fs);
468          return (NULL);
469      }
470      if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
471          printf(gettext("\n*** %s: directory ***\n\n"), fs);
472          return (NULL);
473      }
474      if ((f=Fopen(fs, "r")) == NULL) {
475          fflush(stdout);
476          perror(fs);
477          return (NULL);
478      }
479  
480      if ((c = Getc(f)) == '\f')                  /* end M001 */
481          *clearfirst = 1;
482      else {
483          *clearfirst = 0;
484          Ungetc (c, f);
485      }
486      if ((file_size = (off_t)stbuf.st_size) == 0)
487          file_size = LLONG_MAX;
488      return (f);
489  }
490  
491  /*
492  ** Print out the contents of the file f, one screenful at a time.
493  */
494  
495  #define STOP -10
496  
497  static void
498  screen(register FILE *f, register off_t num_lines)
499  {
500      register int c;
501      register int nchars;
502      int length;                 /* length of current line */
503      static int prev_len = 1;    /* length of previous line */
504  
505      for (;;) {
506          while (num_lines > 0 && !Pause) {
507              if ((nchars = getline (f, &length)) == EOF)
508              {
509                  if (clreol) clreos();
510                  return;
511              }
512              if (ssp_opt && length == 0 && prev_len == 0)
513                  continue;
514              prev_len = length;
515              if (ceol_standout_glitch ||
516  		(enter_standout_mode && *enter_standout_mode == ' ')
517  		&& promptlen > 0)
518                  prmpt_erase (0);
519              /* must clear before drawing line since tabs on some terminals
520               * do not erase what they tab over.
521               */
522              if (clreol)
523                  cleareol ();
524              prbuf (Line, length);
525              if (nchars < promptlen)
526                  prmpt_erase (nchars); /* prmpt_erase () sets promptlen to 0 */
527              else promptlen = 0;
528              /* is this needed?
529               * if (clreol)
530               *  cleareol(); */    /* must clear again in case we wrapped */
531  
532              if (nchars < Mcol || !fold_opt)
533                  putchar('\n');
534              if (nchars == STOP)
535                  break;
536              num_lines--;
537          }
538          fflush(stdout);
539          if ((c = Getc(f)) == EOF)
540          {
541              if (clreol) clreos ();
542              return;
543          }
544  
545          if (Pause && clreol)
546              clreos ();
547          Ungetc (c, f);
548          setjmp (restore);
549          Pause = 0; startup = 0;
550          if ((num_lines = command (NULL, f)) == 0)
551              return;
552          if (hard && promptlen > 0)
553                  prmpt_erase (0);
554          if (noscroll && num_lines == dlines) {
555              if (clreol)
556                  home();
557              else
558                  doclear ();
559          }
560          screen_start.line = Currline;
561          screen_start.chrctr = Ftell (f);
562      }
563  }
564  
565  /*
566  ** Come here if a quit signal is received
567  */
568  /*
569   * sig is put in as a dummy arg to have the compiler not to complain
570   */
571  
572  /* ARGSUSED */
573  void
574  onquit(int sig)
575  {
576      signal(SIGQUIT, SIG_IGN);
577      if (!inwait) {
578          putchar ('\n');
579          if (!startup) {
580              signal(SIGQUIT, onquit);
581              longjmp (restore, 1);
582          }
583          else
584              Pause++;
585      }
586      else if (!dum_opt && notell) {
587          write (2, gettext("[Use q or Q to quit]"), 20);
588          promptlen += 20;
589          notell = 0;
590      }
591      signal(SIGQUIT, onquit);
592  }
593  
594  /*
595  ** Come here if a signal for a window size change is received
596  */
597  /*ARGSUSED*/
598  void
599  chgwinsz(int sig)
600  {
601      struct winsize win;
602  
603      (void) signal(SIGWINCH, SIG_IGN);
604      if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) {
605  	if (win.ws_row != 0) {
606  	    Lpp = win.ws_row;
607  	    nscroll = Lpp/2 - 1;
608  	    if (nscroll <= 0)
609  		nscroll = 1;
610  	    dlines = (off_t)(Lpp - (noscroll ? 1 : 2));
611  	}
612  	if (win.ws_col != 0)
613  	    Mcol = win.ws_col;
614      }
615      (void) signal(SIGWINCH, chgwinsz);
616  }
617  
618  /*
619  ** Clean up terminal state and exit. Also come here if interrupt signal received
620  */
621  
622  /*
623   * sig is put in as a dummy arg to have the compiler not to complain
624   */
625  
626  /* ARGSUSED */
627  void
628  end_it(int sig)
629  {
630  
631      reset_tty ();
632      if (clreol) {
633          putchar ('\r');
634          clreos ();
635          fflush (stdout);
636      }
637      else if (!clreol && (promptlen > 0)) {
638          kill_line ();
639          fflush (stdout);
640      }
641      else
642          write (2, "\n", 1);
643      _exit(exitstat);                    /*M003*/
644  }
645  
646  static void
647  copy_file(register FILE *f)
648  {
649      register int c;
650  
651      while ((c = getc(f)) != EOF)
652          putchar(c);
653  }
654  
655  static char Bell = ctrl('G');
656  
657  
658  /* See whether the last component of the path name "path" is equal to the
659  ** string "string"
660  */
661  
662  int
663  tailequ(char *path, char *string)
664  {
665  	return (!strcmp(basename(path), string));
666  }
667  
668  static void
669  prompt(char *filename)
670  {
671      if (clreol)
672          cleareol ();
673      else if (promptlen > 0)
674          kill_line ();
675      if (!hard) {
676          promptlen = 8;
677          if (enter_standout_mode && exit_standout_mode)
678              putp (enter_standout_mode);
679          if (clreol)
680              cleareol ();
681          pr(gettext("--More--"));
682          if (filename != NULL) {
683              promptlen += printf (gettext("(Next file: %s)"), filename);
684          }
685          else if (!no_intty) {
686              promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size));
687          }
688          if (dum_opt) {
689              promptlen += pr(gettext("[Hit space to continue, Del to abort]"));
690          }
691          if (enter_standout_mode && exit_standout_mode)
692              putp (exit_standout_mode);
693          if (clreol) clreos ();
694          fflush(stdout);
695      }
696      else
697          write (2, &Bell, 1);
698      inwait++;
699  }
700  
701  /*
702   * when run from another program or a shell script, it is
703   * sometimes useful to prevent the next program from scrolling
704   * us off the screen before we get a chance to read this page.
705   *                      -Hans, July 24, 1982
706   */
707  static void
708  wait_eof(void)
709  {
710          if (enter_standout_mode && exit_standout_mode)
711                  putp (enter_standout_mode);
712          promptlen = pr(gettext("--No more--"));          /*M003*/
713          if (dum_opt)
714                  promptlen += pr(gettext("[Hit any key to continue]"));
715          if (enter_standout_mode && exit_standout_mode)
716                  putp(exit_standout_mode);
717          if (clreol) clreos();
718          fflush(stdout);
719          readch();
720          prmpt_erase (0);
721          fflush(stdout);
722  }
723  
724  /*
725  ** Get a logical line
726  */
727  
728  static int
729  getline(register FILE *f, int *length)
730  {
731      register int        c;
732      register char       *p;
733      register int        column;
734      static int          colflg;
735      register int        oldcolumn;
736      int			csno;
737  
738      p = Line;
739      column = 0;
740      oldcolumn = 0;
741      c = Getc (f);
742      if (colflg && c == '\n') {
743          Currline++;
744          c = Getc (f);
745      }
746      while (p < &Line[LINSIZ - 1]) {
747  	csno = csetno(c);
748          if (c == EOF) {
749              if (p > Line) {
750                  *p = '\0';
751                  *length = p - Line;
752                  return (column);
753              }
754              *length = p - Line;
755              return (EOF);
756          }
757  	if (!csno) {
758  	        if (c == '\n') {
759  	            /* detect \r\n.  -Hans */
760  	            if (p>Line && p[-1] == '\r') {
761  	                column = oldcolumn;
762  	                p--;
763  	            }
764  	            Currline++;
765  	            break;
766  	        }
767  	        *p++ = c;
768  	        if (c == '\t')
769  	            if (hardtabs && column < promptlen && !hard) {
770  	                if (clr_eol && !dumb) {
771  	                    column = 1 + (column | 7);
772  	                    putp (clr_eol);
773  	                    promptlen = 0;
774  	                }
775  	                else {
776  	                    for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) {
777  	                        *p++ = ' ';
778  	                    }
779  	                    if (column >= promptlen) promptlen = 0;
780  	                }
781  	            }
782  	            else
783  	                column = 1 + (column | 7);
784  	        else if ((c == '\b') && (ul_opt || !cr_opt) && (column > 0))  /* M008 */
785  	                column--;
786  
787  	        /* this is sort of strange.  what was here before was that
788  	           \r always set column to zero, and the hack above to
789  	           detect \r\n didnt exist.  the net effect is to make
790  	           the current line be overwritten by the prompt if it
791  	           had a \r at the end, and the line start after the \r
792  	           otherwise.  I suppose this is useful for overstriking
793  	           on hard copy terminals, but not on anything glass
794  	           -Hans */
795  
796  	        else if ((c == '\r') && !cr_opt) {
797  	                oldcolumn = column;
798  	                column = 0;
799  	        }
800  	        else if (c == '\f' && stop_opt) {
801  	                p[-1] = '^';
802  	                *p++ = 'L';
803  	                column += 2;
804  	                Pause++;
805  	        }
806  	        else if (c == EOF) {
807  	            *length = p - Line;
808  	            return (column);
809  	        }
810  	        else if (c < ' ' && cr_opt){                    /* M008 begin */
811  	                p[-1] = '^';
812  	                *p++ = c | ('A' - 1);
813  	                column += 2;
814  	        }                                               /* M008 end */
815  	        else if (c >= ' ' && c != RUBOUT)
816  	            column++;
817  	} /* end of code set 0 */
818  	else {
819  		column += scw[csno];
820  		if ( column > Mcol && fold_opt ) {
821  		    column -= scw[csno];
822  		    while ( column < Mcol ) {
823  		        column++;
824  		        *p++ = ' ';
825  		    }
826  		    column = Mcol;
827  		    Ungetc(c,f);
828  		} else {
829  		    int i;
830  		    *p++ = c;
831  		    for(i=1; i<cw[csno];i++)
832  			*p++ = Getc(f);
833  		}
834  	} /* end of codeset 1 ~ 3 */
835          if (column >= Mcol && fold_opt) break;
836          c = Getc (f);
837      }
838      if (column >= Mcol && Mcol > 0) {
839          if (!Wrap) {
840              *p++ = '\n';
841          }
842      }
843      colflg = column == Mcol && fold_opt;
844      if (colflg && eat_newline_glitch && Wrap) {
845  	*p++ = '\n'; /* simulate normal wrap */
846      }
847      *length = p - Line;
848      *p = 0;
849      return (column);
850  }
851  
852  /*
853  ** Erase the rest of the prompt, assuming we are starting at column col.
854  */
855  
856  static void
857  prmpt_erase(register int col)
858  {
859  
860      if (promptlen == 0)
861          return;
862      if (hard) {
863          putchar ('\n');
864      }
865      else {
866          if (col == 0)
867              putchar ('\r');
868          if (!dumb && clr_eol)
869              putp (clr_eol);
870          else
871              for (col = promptlen - col; col > 0; col--)
872                  putchar (' ');
873      }
874      promptlen = 0;
875  }
876  
877  /*
878  ** Erase the current line entirely
879  */
880  
881  static void
882  kill_line(void)
883  {
884      prmpt_erase (0);
885      if (!clr_eol || dumb) putchar ('\r');
886  }
887  
888  /* Print a buffer of n characters */
889  
890  static void
891  prbuf(register char *s, register int n)
892  {
893      char c;                             /* next ouput character */
894      register int state = 0;             /* next output char's UL state */
895      static int pstate = 0;              /* current terminal UL state (off) */
896  
897      while (--n >= 0)
898          if (!ul_opt)
899              putchar (*s++);
900          else {
901              if (n >= 2 && s[0] == '_' && s[1] == '\b') {
902                  n -= 2;
903                  s += 2;
904                  c = *s++;
905                  state = 1;
906              } else if (n >= 2 && s[1] == '\b' && s[2] == '_') {
907                  n -= 2;
908                  c = *s++;
909                  s += 2;
910                  state = 1;
911              } else {
912                  c = *s++;
913                  state = 0;
914              }
915              if (state != pstate)
916                  putp(state ? ULenter : ULexit);
917              pstate = state;
918              putchar(c);
919              if (state && underline_char) {
920                  putp(cursor_left);
921                  putp(underline_char);
922              }
923          }
924      /*
925       * M002
926       * You don't want to stay in standout mode at the end of the line;
927       * on some terminals, this will leave all of the remaining blank
928       * space on the line in standout mode.
929       */
930      if (state && !underline_char) {                       /*M002*/
931              putp(ULexit);                    /*M002*/
932              pstate = 0;                                 /*M002*/
933      }                                                   /*M002*/
934  }
935  
936  /*
937  **  Clear the screen
938  */
939  
940  static void
941  doclear(void)
942  {
943      if (clear_screen && !hard) {
944          putp(clear_screen);
945  
946          /* Put out carriage return so that system doesn't
947          ** get confused by escape sequences when expanding tabs
948          */
949          putchar ('\r');
950          promptlen = 0;
951      }
952  }
953  
954  
955  static int lastcmd, lastp;
956  static off_t lastarg;
957  static int lastcolon;
958  char shell_line[PATH_MAX];
959  
960  /*
961  ** Read a command and do it. A command consists of an optional integer
962  ** argument followed by the command character.  Return the number of lines
963  ** to display in the next screenful.  If there is nothing more to display
964  ** in the current file, zero is returned.
965  */
966  
967  static off_t
968  command(char *filename, register FILE *f)
969  {
970      register off_t nlines;
971      register off_t retval;
972      register int c;
973      char colonch;
974      FILE *helpf;
975      int done;
976      char comchar, cmdbuf[80];
977      char filebuf[128];
978      char *loc;
979  
980  #define ret(val) retval=val;done++;break
981  
982      done = 0;
983      if (!errors)
984          prompt (filename);
985      else
986          errors = 0;
987      for (;;) {
988          nlines = number (&comchar);
989          lastp = colonch = 0;
990          if (comchar == '.') {   /* Repeat last command */
991                  lastp++;
992                  comchar = lastcmd;
993                  nlines = lastarg;
994                  if (lastcmd == ':')
995                          colonch = lastcolon;
996          }
997          lastcmd = comchar;
998          lastarg = nlines;
999  	if((comchar != RUBOUT) && !dum_opt) {
1000          	if (comchar == otty.c_cc[VERASE]) {
1001             		 kill_line ();
1002              		prompt (filename);
1003              		continue;
1004          	}
1005  	}
1006          switch (comchar) {
1007          case ':':
1008              retval = colon (filename, colonch, nlines);
1009              if (retval >= 0)
1010                  done++;
1011              break;
1012  	case 'b':
1013  	case ctrl('B'):
1014  	    {
1015  		register off_t initline;
1016  
1017  		if (no_intty) {
1018  		    write(2, &bell, 1);
1019  		    return (-1);
1020  		}
1021  
1022  		if (nlines == 0) nlines++;
1023  
1024  		putchar ('\r');
1025  		prmpt_erase (0);
1026  		printf ("\n");
1027  		if (clreol)
1028  			cleareol ();
1029  		printf (gettext("...back %lld page"), nlines);
1030  		if (nlines > 1)
1031  			pr ("s\n");
1032  		else
1033  			pr ("\n");
1034  
1035  		if (clreol)
1036  			cleareol ();
1037  		pr ("\n");
1038  
1039  		initline = Currline - dlines * (nlines + 1);
1040  		if (! noscroll)
1041  		    --initline;
1042  		if (initline < 0) initline = 0;
1043  		Fseek(f, 0LL);
1044  		Currline = 0;	/* skiplns() will make Currline correct */
1045  		skiplns(initline, f);
1046  		if (! noscroll) {
1047  		    ret(dlines + 1);
1048  		}
1049  		else {
1050  		    ret(dlines);
1051  		}
1052  	    }
1053          case ' ':
1054          case 'z':
1055              if (nlines == 0) nlines = dlines;
1056              else if (comchar == 'z') dlines = nlines;
1057              ret (nlines);
1058          case 'd':
1059          case ctrl('D'):
1060              if (nlines != 0) nscroll = nlines;
1061              ret (nscroll);
1062          case RUBOUT:
1063          case 'q':
1064          case 'Q':
1065              end_it(0);
1066  	    /*NOTREACHED*/
1067          case 's':
1068          case 'f':
1069              if (nlines == 0) nlines++;
1070              if (comchar == 'f')
1071                  nlines *= dlines;
1072              putchar ('\r');
1073              prmpt_erase (0);
1074              printf ("\n");
1075              if (clreol)
1076                  cleareol ();
1077              printf (gettext("...skipping %lld line"), nlines);
1078              if (nlines > 1)
1079                  pr ("s\n");
1080              else
1081                  pr ("\n");
1082  
1083              if (clreol)
1084                  cleareol ();
1085              pr ("\n");
1086  
1087              while (nlines > 0) {
1088                  while ((c = Getc (f)) != '\n')
1089                      if (c == EOF) {
1090                          retval = 0;
1091                          done++;
1092                          goto endsw;
1093                      }
1094                      Currline++;
1095                      nlines--;
1096              }
1097              ret (dlines);
1098          case '\n':
1099  	    if (nlines != 0)
1100                  dlines = nlines;
1101              else
1102                  nlines = 1;
1103              ret (nlines);
1104          case '\f':
1105              if (!no_intty) {
1106                  doclear ();
1107                  Fseek (f, screen_start.chrctr);
1108                  Currline = screen_start.line;
1109                  ret (dlines);
1110              }
1111              else {
1112                  write (2, &Bell, 1);
1113                  break;
1114              }
1115          case '\'':
1116              if (!no_intty) {
1117                  kill_line ();
1118                  pr (gettext("\n***Back***\n\n"));
1119                  Fseek (f, context.chrctr);
1120                  Currline = context.line;
1121                  ret (dlines);
1122              }
1123              else {
1124                  write (2, &Bell, 1);
1125                  break;
1126              }
1127          case '=':
1128              kill_line ();
1129              promptlen = printf ("%lld", Currline);
1130              fflush (stdout);
1131              break;
1132          case 'n':
1133              lastp++;
1134  	    /*FALLTHROUGH*/
1135          case '/':
1136              if (nlines == 0) nlines++;
1137              kill_line ();
1138              pr ("/");
1139              promptlen = 1;
1140              fflush (stdout);
1141              if (lastp) {
1142                  write (2,"\r", 1);
1143                  search (NULL, f, nlines);       /* Use previous r.e. */
1144              }
1145              else {
1146                  ttyin (cmdbuf, 78, '/');
1147                  write (2, "\r", 1);
1148                  search (cmdbuf, f, nlines);
1149              }
1150              ret (dlines-1);
1151          case '!':
1152              do_shell (filename);
1153              break;
1154          case 'h':
1155          case '?':
1156  	    /*
1157  	     * First get local help file.
1158  	     */
1159  	    loc = setlocale(LC_MESSAGES, 0);
1160  	    sprintf(filebuf, LOCAL_HELP, loc);
1161  
1162              if  ((strcmp(loc, "C") == 0) || (helpf = fopen (filebuf, "r")) == NULL) {
1163  		    if  ((helpf = fopen (HELPFILE, "r")) == NULL)
1164  			error (gettext("Can't open help file"));
1165  	    }
1166              if (noscroll) doclear ();
1167              copy_file (helpf);
1168              fclose (helpf);
1169              prompt (filename);
1170              break;
1171          case 'v':       /* This case should go right before default */
1172              if (!no_intty) {
1173                  kill_line ();
1174                  cmdbuf[0] = '+';
1175                  sprintf(&cmdbuf[1], "%lld", Currline);
1176                  pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]);
1177                  execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0);
1178                  break;
1179              }
1180          default:
1181  		if (dum_opt) {
1182  			kill_line ();
1183  		    	promptlen = pr(gettext("[Press 'h' for instructions.]"));
1184  			fflush (stdout);
1185  	    	}
1186  	    	else
1187              		write (2, &Bell, 1);
1188              break;
1189          }
1190          if (done) break;
1191      }
1192      putchar ('\r');
1193  endsw:
1194      inwait = 0;
1195      notell++;
1196      return (retval);
1197  }
1198  
1199  char ch;
1200  
1201  /*
1202   * Execute a colon-prefixed command.
1203   * Returns <0 if not a command that should cause
1204   * more of the file to be printed.
1205   */
1206  
1207  static int
1208  colon(char *filename, int cmd, off_t nlines)
1209  {
1210          if (cmd == 0)
1211                  ch = readch ();
1212          else
1213                  ch = cmd;
1214          lastcolon = ch;
1215          switch (ch) {
1216          case 'f':
1217                  kill_line ();
1218                  if (!no_intty)
1219                          promptlen = printf (gettext("\"%s\" line %lld"),
1220  					    fnames[fnum], Currline);
1221                  else
1222                          promptlen = printf(
1223  			 gettext("[Not a file] line %lld"), Currline);
1224                  fflush (stdout);
1225                  return (-1);
1226          case 'n':
1227                  if (nlines == 0) {
1228                          if (fnum >= nfiles - 1)
1229                                  end_it(0);
1230                          nlines++;
1231                  }
1232                  putchar ('\r');
1233                  prmpt_erase (0);
1234                  skipf ((int)nlines);
1235                  return (0);
1236          case 'p':
1237                  if (no_intty) {
1238                          write (2, &Bell, 1);
1239                          return (-1);
1240                  }
1241                  putchar ('\r');
1242                  prmpt_erase (0);
1243                  if (nlines == 0)
1244                          nlines++;
1245                  skipf ((int)-nlines);
1246                  return (0);
1247          case '!':
1248                  do_shell (filename);
1249                  return (-1);
1250          case 'q':
1251          case 'Q':
1252                  end_it(0);
1253          default:
1254                  write (2, &Bell, 1);
1255                  return (-1);
1256          }
1257  }
1258  
1259  /*
1260  ** Read a decimal number from the terminal. Set cmd to the non-digit which
1261  ** terminates the number.
1262  */
1263  
1264  static int
1265  number(char *cmd)
1266  {
1267          register int i;
1268  
1269          i = 0; ch = otty.c_cc[VKILL];
1270          for (;;) {
1271                  ch = readch ();
1272                  if (ch >= '0' && ch <= '9') {
1273                          i = i*10 + ch - '0';
1274                  } else if (ch == RUBOUT) {
1275                          i = 0;
1276                          *cmd = ch;
1277                          break;
1278                  } else if (ch == otty.c_cc[VKILL]) {
1279                          i = 0;
1280                  } else {
1281                          *cmd = ch;
1282                          break;
1283                  }
1284          }
1285          return (i);
1286  }
1287  
1288  static void
1289  do_shell(char *filename)
1290  {
1291          char cmdbuf[80];
1292  
1293          kill_line ();
1294          pr ("!");
1295          fflush (stdout);
1296          promptlen = 1;
1297          if (lastp)
1298                  pr (shell_line);
1299          else {
1300                  ttyin (cmdbuf, 78, '!');
1301                  if (expand (shell_line, cmdbuf)) {
1302                          kill_line ();
1303                          promptlen = printf ("!%s", shell_line);
1304                  }
1305          }
1306          fflush (stdout);
1307          write (2, "\n", 1);
1308          promptlen = 0;
1309          shellp = 1;
1310          execute (filename, shell, shell, "-c", shell_line, 0);
1311  }
1312  
1313  /*
1314  ** Search for nth ocurrence of regular expression contained in buf in the file
1315  */
1316  
1317  static void
1318  search(char buf[], FILE *file, register off_t n)
1319  {
1320      off_t startline = Ftell (file);
1321      register off_t line1 = startline;
1322      register off_t line2 = startline;
1323      register off_t line3 = startline;
1324      register off_t lncount;
1325      off_t saveln;
1326      static char *s = NULL;
1327      static char lastbuf[80];
1328  
1329      if (buf != NULL) {
1330  	if (s != NULL)
1331  		free(s);
1332  	if (*buf != '\0') {
1333  		if ((s = regcmp(buf, (char *) NULL)) == NULL)
1334  			error(gettext("Regular expression botch"));
1335  		else
1336  			strcpy(lastbuf, buf);
1337  	} else {
1338  		if ((s = regcmp(lastbuf, (char *) NULL)) == NULL)
1339  			error(gettext("No previous regular expression"));
1340  	}
1341      } else {
1342  	if (s == NULL)
1343  	    error(gettext("No previous regular expression"));
1344      }
1345      context.line = saveln = Currline;
1346      context.chrctr = startline;
1347      lncount = 0;
1348      while (!feof (file)) {
1349          line3 = line2;
1350          line2 = line1;
1351          line1 = Ftell (file);
1352          rdline (file);
1353          lncount++;
1354          if (regex(s, Line) != NULL)
1355                  if (--n == 0) {
1356                      if (lncount > 3 || (lncount > 1 && no_intty))
1357                      {
1358                          pr ("\n");
1359                          if (clreol)
1360                              cleareol ();
1361                          pr(gettext("...skipping\n"));
1362                      }
1363                      if (!no_intty) {
1364                          Currline -= (lncount >= 3 ? 3 : lncount);
1365                          Fseek (file, line3);
1366                          if (noscroll)
1367                              if (clreol) {
1368                                  home ();
1369                                  cleareol ();
1370                              }
1371                              else
1372                                  doclear ();
1373                      }
1374                      else {
1375                          kill_line ();
1376                          if (noscroll)
1377                              if (clreol) {
1378                                  home ();
1379                                  cleareol ();
1380                              } else
1381                                  doclear ();
1382                          pr (Line);
1383                          putchar ('\n');
1384                      }
1385                      break;
1386                  }
1387      }
1388      if (feof (file)) {
1389          if (!no_intty) {
1390              Currline = saveln;
1391              Fseek (file, startline);
1392          }
1393          else {
1394              pr (gettext("\nPattern not found\n"));
1395              end_it (0);
1396          }
1397          error (gettext("Pattern not found"));
1398      }
1399  }
1400  
1401  #define MAXARGS 10 /* enough for 9 args. We are only passed 4 now */
1402  
1403  static void
1404  execute (char *filename, char *cmd, ...)
1405  {
1406          pid_t id;
1407  	va_list ap;
1408  	char *argp[MAXARGS];
1409  	int  count;
1410  
1411          fflush (stdout);
1412          reset_tty ();
1413          while ((id = fork ()) < 0)
1414              sleep (5);
1415          if (id == 0) {
1416              if (no_intty) {     /*M002*/
1417                  close(0);       /*M002*/
1418                  dup(2);         /*M002*/
1419              }                   /*M002*/
1420  	    va_start(ap, cmd);
1421  	    count = 0;
1422  	    do {
1423  #ifndef lint
1424  		argp[count] = va_arg(ap, char *);
1425  #else
1426  		ap = ap;
1427  #endif
1428  		count++;
1429  		if (count > MAXARGS)
1430  			error (gettext("Too many arguments in execute()\n"));
1431  	    } while (argp[count - 1] != NULL);
1432  	    va_end(ap);
1433  	    execvp(cmd, argp);
1434              write (2, "exec failed\n", 12);
1435              exit (1);
1436          }
1437          signal (SIGINT, SIG_IGN);
1438          signal (SIGQUIT, SIG_IGN);
1439  	signal (SIGWINCH, SIG_IGN);
1440  #ifdef SIGTSTP
1441          if (catch_susp)
1442              signal(SIGTSTP, SIG_DFL);
1443  #endif
1444          wait ((pid_t)0);
1445          signal (SIGINT, end_it);
1446          signal (SIGQUIT, onquit);
1447  	signal (SIGWINCH, chgwinsz);
1448  #ifdef SIGTSTP
1449          if (catch_susp)
1450              signal(SIGTSTP, onsusp);
1451  #endif
1452  	/*
1453  	 * Since we were ignoring window change signals while we executed
1454  	 * the command, we must assume the window changed.
1455  	 */
1456  	(void) chgwinsz(0);
1457  	set_tty ();
1458  
1459          pr ("------------------------\n");
1460          prompt (filename);
1461  }
1462  /*
1463  ** Skip n lines in the file f
1464  */
1465  
1466  static void
1467  skiplns(register off_t n, register FILE *f)
1468  {
1469      register int c;
1470  
1471      while (n > 0) {
1472          while ((c = Getc (f)) != '\n')
1473              if (c == EOF)
1474                  return;
1475              n--;
1476              Currline++;
1477      }
1478  }
1479  
1480  /*
1481  ** Skip nskip files in the file list (from the command line). Nskip may be
1482  ** negative.
1483  */
1484  
1485  static void
1486  skipf(register int nskip)
1487  {
1488      if (nskip == 0) return;
1489      if (nskip > 0) {
1490          if (fnum + nskip > nfiles - 1)
1491              nskip = nfiles - fnum - 1;
1492      }
1493      else if (within)
1494          ++fnum;
1495      fnum += nskip;
1496      if (fnum < 0)
1497          fnum = 0;
1498      pr (gettext("\n...Skipping "));
1499      pr ("\n");
1500      if (clreol)
1501          cleareol ();
1502      if (nskip > 0)
1503  	printf(gettext("...Skipping to file %s\n"), fnames[fnum]);
1504      else
1505  	printf(gettext("...Skipping back to file %s\n"), fnames[fnum]);
1506      if (clreol)
1507          cleareol ();
1508      pr ("\n");
1509      --fnum;
1510  }
1511  
1512  /*----------------------------- Terminal I/O -------------------------------*/
1513  
1514  static void
1515  initterm(void)
1516  {
1517      int         erret = 0;
1518  
1519      setbuf(stdout, obuf);
1520      if (!(no_tty = ioctl(1, TCGETA, &otty))) {
1521  	if (setupterm(NULL, 1, &erret) != OK) {
1522              dumb++; ul_opt = 0;
1523          }
1524          else {
1525  	    reset_shell_mode();
1526              if (((Lpp = lines) < 0) || hard_copy) {
1527                  hard++; /* Hard copy terminal */
1528                  Lpp = 24;
1529              }
1530              if (tailequ(fnames[0], "page") || !hard && (scroll_forward == NULL))
1531                  noscroll++;
1532              if ((Mcol = columns) < 0)
1533                  Mcol = 80;
1534              Wrap = tigetflag("am");
1535              /*
1536               *  Set up for underlining:  some terminals don't need it;
1537               *  others have start/stop sequences, still others have an
1538               *  underline char sequence which is assumed to move the
1539               *  cursor forward one character.  If underline sequence
1540               *  isn't available, settle for standout sequence.
1541               */
1542  
1543              if (transparent_underline || over_strike)
1544                  ul_opt = 0;
1545              if ((ULenter = tigetstr("smul")) == NULL &&
1546                  (!underline_char) && (ULenter = tigetstr("smso")) == NULL)
1547                  ULenter = "";
1548              if ((ULexit = tigetstr("rmul")) == NULL &&
1549                  (!underline_char) && (ULexit = tigetstr("rmso")) == NULL)
1550                  ULexit = "";
1551          }
1552          if ((shell = getenv("SHELL")) == NULL)
1553              shell = "/usr/bin/sh";
1554      }
1555      no_intty = ioctl(0, TCGETA, &otty);
1556      ioctl(2, TCGETA, &otty);
1557      hardtabs = !(otty.c_oflag & TAB3);
1558  }
1559  
1560  static int
1561  readch(void)
1562  {
1563          char ch;
1564          extern int errno;
1565  
1566          if (read (2, &ch, 1) <= 0)
1567                  if (errno != EINTR)
1568                          end_it(0);		/* clean up before exiting */
1569                  else
1570                          ch = otty.c_cc[VKILL];
1571          return (ch);
1572  }
1573  
1574  static char BS = '\b';
1575  static char CARAT = '^';
1576  
1577  static void
1578  ttyin(char buf[], register int nmax, char pchar)
1579  {
1580      register char *sptr;
1581      register unsigned char ch;
1582      int LengthBuffer[80];
1583      int *BufferPointer;
1584      int csno;
1585      register int slash = 0;
1586      int maxlen;
1587      char cbuf;
1588  
1589      BufferPointer = LengthBuffer;
1590      sptr = buf;
1591      maxlen = 0;
1592      while (sptr - buf < nmax) {
1593          if (promptlen > maxlen)
1594  	    maxlen = promptlen;
1595          ch = readch ();
1596          csno = csetno(ch);
1597          if (!csno) {
1598              if (ch == '\\') {
1599                  slash++;
1600              } else if ((ch == otty.c_cc[VERASE]) && !slash) {
1601                  if (sptr > buf) {
1602                      --promptlen;
1603                      write (2, &BS, 1);
1604  		    sptr -= (*--BufferPointer);
1605                      if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) {
1606                          --promptlen;
1607                          write (2, &BS, 1);
1608                      }
1609                      continue;
1610                  } else {
1611                      if (!clr_eol)
1612  			promptlen = maxlen;
1613                      longjmp (restore, 1);
1614                  }
1615              } else if ((ch == otty.c_cc[VKILL]) && !slash) {
1616                  if (hard) {
1617                      show(ch);
1618                      putchar ('\n');
1619                      putchar (pchar);
1620                  } else {
1621                      putchar ('\r');
1622  		    putchar (pchar);
1623                      if (clr_eol)
1624                          prmpt_erase (1);
1625                      promptlen = 1;
1626                  }
1627                  sptr = buf;
1628                  fflush (stdout);
1629                  continue;
1630              }
1631              if (slash && (ch == otty.c_cc[VKILL] || ch == otty.c_cc[VERASE])) {
1632                  write (2, &BS, 1);
1633  	        sptr -= (*--BufferPointer);
1634              }
1635              if (ch != '\\')
1636                  slash = 0;
1637  	    *BufferPointer++ = 1;
1638              *sptr++ = ch;
1639              if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
1640                  ch += ch == RUBOUT ? -0100 : 0100;
1641                  write (2, &CARAT, 1);
1642                  promptlen++;
1643              }
1644              cbuf = ch;
1645              if (ch != '\n' && ch != ESC) {
1646                  write (2, &cbuf, 1);
1647                  promptlen++;
1648              } else
1649                  break;
1650              /* end of code set 0 */
1651          } else {
1652  	    int i;
1653  	    u_char buffer[5];
1654  
1655  	    *BufferPointer++ = cw[csno];
1656  	    buffer[0] = *sptr++ = ch;
1657  	    for(i=1; i<cw[csno]; i++) {
1658  	        buffer[i] = *sptr++ = readch();
1659  	    }
1660  	    buffer[i]='\0';
1661  	    write(2, buffer, strlen((char *)buffer));
1662  	}
1663      }
1664      *--sptr = '\0';
1665      if (!clr_eol) promptlen = maxlen;
1666      if (sptr - buf >= nmax - 1)
1667          error (gettext("Line too long"));
1668  }
1669  
1670  static int
1671  expand(char *outbuf, char *inbuf)
1672  {
1673  	char *in_str;
1674  	char *out_str;
1675  	char ch;
1676  	char temp[PATH_MAX];
1677  	int changed = 0;
1678  
1679      in_str = inbuf;
1680      out_str = temp;
1681      while ((ch = *in_str++) != '\0')
1682          switch (ch) {
1683          case '%':
1684              if (!no_intty) {
1685  		if (strlcpy(out_str, fnames[fnum], sizeof (temp))
1686  		    >= sizeof (temp))
1687  			error(gettext("Command too long"));
1688                  out_str += strlen (fnames[fnum]);
1689                  changed++;
1690              }
1691              else
1692                  *out_str++ = ch;
1693              break;
1694          case '!':
1695              if (!shellp)
1696                  error (gettext("No previous command to substitute for"));
1697  	    if (strlcpy(out_str, shell_line, sizeof (temp)) >= sizeof (temp))
1698  		error(gettext("Command too long"));
1699              out_str += strlen (shell_line);
1700              changed++;
1701              break;
1702          case '\\':
1703              if (*in_str == '%' || *in_str == '!') {
1704                  *out_str++ = *in_str++;
1705                  break;
1706              }
1707          default:
1708              *out_str++ = ch;
1709          }
1710      *out_str++ = '\0';
1711  	if (strlcpy(outbuf, temp, sizeof (shell_line)) >= sizeof (shell_line))
1712  		error(gettext("Command too long"));
1713      return (changed);
1714  }
1715  
1716  static void
1717  show(register char ch)
1718  {
1719      char cbuf;
1720  
1721      if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
1722          ch += ch == RUBOUT ? -0100 : 0100;
1723          write (2, &CARAT, 1);
1724          promptlen++;
1725      }
1726      cbuf = ch;
1727      write (2, &cbuf, 1);
1728      promptlen++;
1729  }
1730  
1731  static void
1732  error (char *mess)
1733  {
1734      if (clreol)
1735          cleareol ();
1736      else
1737          kill_line ();
1738      promptlen += strlen (mess);
1739      if (enter_standout_mode && exit_standout_mode) {
1740          putp (enter_standout_mode);
1741          pr(mess);
1742          putp (exit_standout_mode);
1743      }
1744      else
1745          pr (mess);
1746      fflush(stdout);
1747      errors++;
1748      longjmp (restore, 1);
1749  }
1750  
1751  
1752  static void
1753  set_tty(void)
1754  {
1755          ioctl(2, TCGETA, &otty);     /* save old tty modes */
1756          ioctl(2, TCGETA, &ntty);
1757          ntty.c_lflag &= ~ECHO & ~ICANON;
1758          ntty.c_cc[VMIN] = (char)1;
1759          ntty.c_cc[VTIME] = (char)0;
1760          ioctl (2, TCSETAF, &ntty);        /* set new tty modes */
1761  }
1762  
1763  static void
1764  reset_tty(void)
1765  {
1766          ioctl (2, TCSETAF, &otty);        /* reset tty modes */
1767  }
1768  
1769  static void
1770  rdline(register FILE *f)
1771  {
1772      register int c;
1773      register char *p;
1774  
1775      p = Line;
1776      while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1)
1777          *p++ = c;
1778      if (c == '\n')
1779          Currline++;
1780      *p = '\0';
1781  }
1782  
1783  /* Come here when we get a suspend signal from the terminal */
1784  
1785  /*
1786   * sig is put in as a dummy arg to have the compiler not to complain
1787   */
1788  #ifdef SIGTSTP
1789  /* ARGSUSED */
1790  void
1791  onsusp(int sig)
1792  {
1793      /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
1794      signal(SIGTTOU, SIG_IGN);
1795      reset_tty ();
1796      fflush (stdout);
1797      signal(SIGTTOU, SIG_DFL);
1798  
1799      /* Send the TSTP signal to suspend our process group */
1800      kill (0, SIGTSTP);
1801      /* Pause for station break */
1802  
1803      /* We're back */
1804      signal (SIGTSTP, onsusp);
1805      set_tty ();
1806      if (inwait)
1807              longjmp (restore, 1);
1808  }
1809  #endif
1810