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