]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - text-utils/more.c
2 * Copyright (C) 1980 The Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 ** more.c - General purpose tty output filter and file perusal program
21 ** by Eric Shienbrood, UC Berkeley
23 ** modified by Geoff Peck, UCB to add underlining, single spacing
24 ** modified by John Foderaro, UCB to add -c and MORE environment variable
25 ** modified by Erik Troan <ewt@redhat.com> to be more posix and so compile
27 ** modified by Kars de Jong <jongk@cs.utwente.nl> to use terminfo instead
34 #include <stdlib.h> /* for alloca() */
35 #include <sys/param.h>
41 #include <sys/ioctl.h>
54 #define HELPFILE "/usr/lib/more.help"
55 #define VI "/usr/bin/vi"
57 #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m))
58 #define Ftell(f) file_pos
59 #define Fseek(f,off) (file_pos=off,fseek(f,off,0))
60 #define Getc(f) (++file_pos, getc(f))
61 #define Ungetc(c,f) (--file_pos, ungetc(c,f))
63 #define stty(fd,argp) tcsetattr(fd,TCSANOW,argp)
65 /* some function declarations */
72 void error (char *mess
);
73 void do_shell (char *filename
);
74 int colon (char *filename
, int cmd
, int nlines
);
75 int expand (char *outbuf
, char *inbuf
);
76 void argscan(char *s
);
77 void rdline (register FILE *f
);
78 void copy_file(register FILE *f
);
79 void search(char buf
[], FILE *file
, register int n
);
80 void skipf (register int nskip
);
81 void skiplns(register int n
, register FILE *f
);
82 void screen (register FILE *f
, register int num_lines
);
83 int command (char *filename
, register FILE *f
);
84 void erasep (register int col
);
85 void show (register char ch
);
90 void ttyin (char buf
[], register int nmax
, char pchar
);
91 int number(char *cmd
);
93 int get_line(register FILE *f
, int *length
);
94 void prbuf (register char *s
, register int n
);
95 int xprintf (char *fmt
, ...);
96 void execute (char *filename
, char *cmd
, ...);
97 void errwrite (char *txt
);
98 void errwrite1 (char *sym
);
102 #define ctrl(letter) (letter & 077)
103 #define RUBOUT '\177'
107 struct termios otty
, savetty0
;
108 long file_pos
, file_size
;
109 int fnum
, no_intty
, no_tty
, slow_tty
;
111 void onquit(), onsusp(), chgwinsz(), end_it();
112 int nscroll
= 11; /* Number of lines scrolled by 'd' */
113 int fold_opt
= 1; /* Fold long lines */
114 int stop_opt
= 1; /* Stop after form feeds */
115 int ssp_opt
= 0; /* Suppress white space */
116 int ul_opt
= 1; /* Underline as best we can */
118 int Currline
; /* Line we are currently at */
124 int bad_so
; /* True if overwriting does not turn off standout */
125 int inwait
, Pause
, errors
;
126 int within
; /* true if we are within a file,
127 false if we are between files */
128 int hard
, dumb
, noscroll
, hardtabs
, clreol
, eatnl
;
129 int catch_susp
; /* We should catch the SIGTSTP signal */
130 char **fnames
; /* The list of file names */
131 int nfiles
; /* Number of files left to process */
132 char *shell
; /* The name of the shell to use */
133 int shellp
; /* A previous shell command exists */
136 char Line
[LINSIZ
]; /* Line buffer */
137 int Lpp
= 24; /* lines per page */
138 char *Clear
; /* clear screen */
139 char *eraseln
; /* erase line */
140 char *Senter
, *Sexit
;/* enter and exit standout mode */
141 char *ULenter
, *ULexit
; /* enter and exit underline mode */
142 char *chUL
; /* underline character */
143 char *chBS
; /* backspace character */
144 char *Home
; /* go to home */
145 char *cursorm
; /* cursor movement */
146 char cursorhome
[40]; /* contains cursor movement to home */
147 char *EodClr
; /* clear rest of screen */
149 int Mcol
= 80; /* number of columns */
150 int Wrap
= 1; /* set if automargins */
151 int soglitch
; /* terminal has standout mode glitch */
152 int ulglitch
; /* terminal has underline mode glitch */
153 int pstate
= 0; /* current UL state */
158 } context
, screen_start
;
159 /* extern */ char PC
; /* pad character */
167 int main(int argc
, char **argv
) {
181 /* avoid gcc complaints about register variables that
182 may be clobbered by a longjmp, by forcing our variables here
183 to be non-register */
184 Fdummy(&f
); idummy(&left
); idummy(&prnames
);
185 idummy(&initopt
); idummy(&srchopt
); idummy(&initline
);
189 setlocale(LC_ALL
, "");
194 if((s
= getenv("MORE")) != NULL
) argscan(s
);
195 while (--nfiles
> 0) {
196 if ((ch
= (*++fnames
)[0]) == '-') {
199 else if (ch
== '+') {
203 for (++s
, p
= initbuf
; p
< initbuf
+ 79 && *s
!= '\0';)
209 for (initline
= 0; *s
!= '\0'; s
++)
211 initline
= initline
*10 + *s
-'0';
217 /* allow clreol only if Home and eraseln and EodClr strings are
218 * defined, and in that case, make sure we are in noscroll mode
222 if((Home
== NULL
) || (*Home
== '\0') ||
223 (eraseln
== NULL
) || (*eraseln
== '\0') ||
224 (EodClr
== NULL
) || (*EodClr
== '\0') )
229 dlines
= Lpp
- (noscroll
? 1 : 2);
233 if (!no_intty
&& nfiles
== 0) {
236 p
= rindex(argv
[0], '/');
237 fputs("usage: ",stderr
);
238 fputs(p
? p
+ 1 : argv
[0],stderr
);
239 fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr
);
245 signal(SIGQUIT
, onquit
);
246 signal(SIGINT
, end_it
);
248 signal(SIGWINCH
, chgwinsz
);
250 if (signal (SIGTSTP
, SIG_IGN
) == SIG_DFL
) {
251 signal(SIGTSTP
, onsusp
);
254 stty (fileno(stderr
), &otty
);
260 if ((ch
= Getc (f
)) == '\f')
264 if (noscroll
&& (ch
!= EOF
)) {
273 search (initbuf
, stdin
, 1);
278 skiplns (initline
, stdin
);
279 screen (stdin
, left
);
286 while (fnum
< nfiles
) {
287 if ((f
= checkf (fnames
[fnum
], &clearit
)) != NULL
) {
288 context
.line
= context
.chrctr
= 0;
290 if (firstf
) setjmp (restore
);
294 search (initbuf
, f
, 1);
299 skiplns (initline
, f
);
301 else if (fnum
< nfiles
&& !no_tty
) {
303 left
= command (fnames
[fnum
], f
);
306 if ((noscroll
|| clearit
) && (file_size
!= LONG_MAX
)) {
317 pr("::::::::::::::");
321 if(clreol
) cleareol();
322 xprintf("%s\n", fnames
[fnum
]);
323 if(clreol
) cleareol();
324 xprintf("::::::::::::::\n");
339 screen_start
.line
= screen_start
.chrctr
= 0L;
340 context
.line
= context
.chrctr
= 0L;
349 void argscan(char *s
) {
354 case '0': case '1': case '2':
355 case '3': case '4': case '5':
356 case '6': case '7': case '8':
362 dlines
= dlines
*10 + *s
- '0';
392 ** Check whether the file named by fs is an ASCII file which the user may
393 ** access. If it is, return the opened file. Otherwise return NULL.
397 checkf (fs
, clearfirst
)
405 if (stat (fs
, &stbuf
) == -1) {
406 (void)fflush(stdout
);
410 return((FILE *)NULL
);
412 if ((stbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
413 xprintf("\n*** %s: directory ***\n\n", fs
);
414 return((FILE *)NULL
);
416 if ((f
= Fopen(fs
, "r")) == NULL
) {
417 (void)fflush(stdout
);
419 return((FILE *)NULL
);
422 return((FILE *)NULL
);
424 *clearfirst
= c
== '\f';
426 if ((file_size
= stbuf
.st_size
) == 0)
427 file_size
= LONG_MAX
;
433 * check for file magic numbers. This code would best be shared with
434 * the file(1) program or, perhaps, more should not try and be so smart?
443 if (fread(twobytes
, 2, 1, f
) == 1) {
444 switch(twobytes
[0] + (twobytes
[1]<<8)) {
445 case OMAGIC
: /* 0407 */
446 case NMAGIC
: /* 0410 */
447 case ZMAGIC
: /* 0413 */
451 case 0x457f: /* simple ELF detection */
452 xprintf("\n******** %s: Not a text file ********\n\n", fs
);
457 (void)fseek(f
, 0L, SEEK_SET
); /* rewind() not necessary */
462 ** Print out the contents of the file f, one screenful at a time.
467 void screen (register FILE *f
, register int num_lines
)
471 int length
; /* length of current line */
472 static int prev_len
= 1; /* length of previous line */
475 while (num_lines
> 0 && !Pause
) {
476 if ((nchars
= get_line (f
, &length
)) == EOF
)
482 if (ssp_opt
&& length
== 0 && prev_len
== 0)
485 if (bad_so
|| ((Senter
&& *Senter
== ' ') && (promptlen
> 0)))
487 /* must clear before drawing line since tabs on some terminals
488 * do not erase what they tab over.
492 prbuf (Line
, length
);
493 if (nchars
< promptlen
)
494 erasep (nchars
); /* erasep () sets promptlen to 0 */
498 * cleareol(); * must clear again in case we wrapped *
500 if (nchars
< Mcol
|| !fold_opt
)
501 prbuf("\n", 1); /* will turn off UL if necessary */
511 if ((c
= Getc(f
)) == EOF
)
522 Pause
= 0; startup
= 0;
523 if ((num_lines
= command (NULL
, f
)) == 0)
525 if (hard
&& promptlen
> 0)
527 if (noscroll
&& num_lines
>= dlines
)
534 screen_start
.line
= Currline
;
535 screen_start
.chrctr
= Ftell (f
);
540 ** Come here if a quit signal is received
545 signal(SIGQUIT
, SIG_IGN
);
549 signal(SIGQUIT
, onquit
);
550 longjmp (restore
, 1);
555 else if (!dum_opt
&& notell
) {
556 errwrite("[Use q or Q to quit]");
560 signal(SIGQUIT
, onquit
);
564 ** Come here if a signal for a window size change is received
572 (void) signal(SIGWINCH
, SIG_IGN
);
573 if (ioctl(fileno(stdout
), TIOCGWINSZ
, &win
) != -1) {
574 if (win
.ws_row
!= 0) {
579 dlines
= Lpp
- (noscroll
? 1 : 2);
584 (void) signal(SIGWINCH
, chgwinsz
);
589 ** Clean up terminal state and exit. Also come here if interrupt signal received
601 else if (!clreol
&& (promptlen
> 0)) {
610 void copy_file(register FILE *f
) {
613 while ((c
= getc(f
)) != EOF
)
617 /* Simplified printf function */
619 int xprintf (char *fmt
, ...)
628 while ((ch
= *fmt
++) != '%') {
636 ccount
+= printd (va_arg(ap
, int));
639 ccount
+= pr (va_arg(ap
, char *));
657 ** Print an integer as a string of decimal digits,
658 ** returning the length of the print representation.
666 nchars
= 1 + printd(a
);
669 putchar (n
% 10 + '0');
673 /* Put the print representation of an integer into a string */
676 void Sprintf (int n
) {
681 *sptr
++ = n
% 10 + '0';
684 void scanstr (int n
, char *str
)
691 #define ringbell() errwrite("\007");
706 /* See whether the last component of the path name "path" is equal to the
710 int tailequ (path
, string
)
712 register char *string
;
716 tail
= path
+ strlen(path
);
718 if (*(--tail
) == '/')
721 while (*tail
++ == *string
++)
727 void prompt (filename
)
732 else if (promptlen
> 0)
736 if (Senter
&& Sexit
) {
738 promptlen
+= (2 * soglitch
);
743 if (filename
!= NULL
) {
744 promptlen
+= xprintf ("(Next file: %s)", filename
);
746 else if (!no_intty
) {
747 promptlen
+= xprintf ("(%d%%)", (int)((file_pos
* 100) / file_size
));
750 promptlen
+= pr("[Press space to continue, 'q' to quit.]");
764 ** Get a logical line
767 int get_line(register FILE *f
, int *length
)
777 if (colflg
&& c
== '\n') {
781 while (p
< &Line
[LINSIZ
- 1]) {
797 if (!hardtabs
|| (column
< promptlen
&& !hard
)) {
798 if (hardtabs
&& eraseln
&& !dumb
) {
799 column
= 1 + (column
| 7);
804 for (--p
; p
< &Line
[LINSIZ
- 1];) {
806 if ((++column
& 7) == 0)
809 if (column
>= promptlen
) promptlen
= 0;
813 column
= 1 + (column
| 7);
814 } else if (c
== '\b' && column
> 0) {
816 } else if (c
== '\r') {
825 } else if (c
== '\f' && stop_opt
) {
830 } else if (c
== EOF
) {
836 if (column
>= Mcol
&& fold_opt
) break;
839 if (column
>= Mcol
&& Mcol
> 0) {
844 colflg
= column
== Mcol
&& fold_opt
;
845 if (colflg
&& eatnl
&& Wrap
) {
846 *p
++ = '\n'; /* simulate normal wrap */
854 ** Erase the rest of the prompt, assuming we are starting at column col.
857 void erasep (register int col
)
868 if (!dumb
&& eraseln
)
871 for (col
= promptlen
- col
; col
> 0; col
--)
878 ** Erase the current line entirely
884 if (!eraseln
|| dumb
)
889 * force clear to end of line
902 ** Print string and return number of characters
910 for (s
= s1
; (c
= *s
++) != 0; )
912 return (int) (s
- s1
- 1);
916 /* Print a buffer of n characters */
918 void prbuf (register char *s
, register int n
)
920 register char c
; /* next output character */
921 register int state
; /* next output char's UL state */
922 #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_')))
928 if (*s
== ' ' && pstate
== 0 && ulglitch
&& wouldul(s
+1, n
-1)) {
932 if ((state
= wouldul(s
, n
)) != 0) {
933 c
= (*s
== '_')? s
[2] : *s
;
938 if (state
!= pstate
) {
939 if (c
== ' ' && state
== 0 && ulglitch
&& wouldul(s
, n
-1))
942 putp(state
? ULenter
: ULexit
);
944 if (c
!= ' ' || pstate
== 0 || state
!= 0 || ulglitch
== 0)
946 if (state
&& *chUL
) {
960 if (Clear
&& !hard
) {
963 /* Put out carriage return so that system doesn't
964 ** get confused by escape sequences when expanding tabs
972 * Go to home position
980 static int lastcmd
, lastarg
, lastp
;
981 static int lastcolon
;
982 char shell_line
[132];
985 ** Read a command and do it. A command consists of an optional integer
986 ** argument followed by the command character. Return the number of lines
987 ** to display in the next screenful. If there is nothing more to display
988 ** in the current file, zero is returned.
991 int command (char *filename
, register FILE *f
)
994 register int retval
= 0;
999 char comchar
, cmdbuf
[80];
1001 #define ret(val) retval=val;done++;break
1009 nlines
= number (&comchar
);
1010 lastp
= colonch
= 0;
1011 if (comchar
== '.') { /* Repeat last command */
1016 colonch
= lastcolon
;
1020 if (comchar
== otty
.c_cc
[VERASE
]) {
1027 retval
= colon (filename
, colonch
, nlines
);
1034 register int initline
;
1041 if (nlines
== 0) nlines
++;
1048 xprintf ("...back %d page", nlines
);
1058 initline
= Currline
- dlines
* (nlines
+ 1);
1061 if (initline
< 0) initline
= 0;
1063 Currline
= 0; /* skiplns() will make Currline correct */
1064 skiplns(initline
, f
);
1074 if (nlines
== 0) nlines
= dlines
;
1075 else if (comchar
== 'z') dlines
= nlines
;
1079 if (nlines
!= 0) nscroll
= nlines
;
1086 if (nlines
== 0) nlines
++;
1094 xprintf ("...skipping %d line", nlines
);
1104 while (nlines
> 0) {
1105 while ((c
= Getc (f
)) != '\n')
1124 Fseek (f
, screen_start
.chrctr
);
1125 Currline
= screen_start
.line
;
1135 pr ("\n***Back***\n\n");
1136 Fseek (f
, context
.chrctr
);
1137 Currline
= context
.line
;
1146 promptlen
= printd (Currline
);
1152 if (nlines
== 0) nlines
++;
1159 search (NULL
, f
, nlines
); /* Use previous r.e. */
1162 ttyin (cmdbuf
, sizeof(cmdbuf
)-2, '/');
1164 search (cmdbuf
, f
, nlines
);
1168 do_shell (filename
);
1172 if ((helpf
= fopen (HELPFILE
, "r")) == NULL
)
1173 error ("Can't open help file");
1174 if (noscroll
) doclear ();
1179 case 'v': /* This case should go right before default */
1183 scanstr (Currline
- dlines
< 0 ? 0
1184 : Currline
- (dlines
+ 1) / 2, &cmdbuf
[1]);
1185 pr ("vi "); pr (cmdbuf
); putchar (' '); pr (fnames
[fnum
]);
1186 execute (filename
, VI
, "vi", cmdbuf
, fnames
[fnum
], 0);
1192 if (Senter
&& Sexit
) {
1194 promptlen
= pr ("[Press 'h' for instructions.]") + (2 * soglitch
);
1198 promptlen
= pr ("[Press 'h' for instructions.]");
1217 * Execute a colon-prefixed command.
1218 * Returns <0 if not a command that should cause
1219 * more of the file to be printed.
1222 int colon (char *filename
, int cmd
, int nlines
)
1233 promptlen
= xprintf ("\"%s\" line %d", fnames
[fnum
], Currline
);
1235 promptlen
= xprintf ("[Not a file] line %d", Currline
);
1240 if (fnum
>= nfiles
- 1)
1260 do_shell (filename
);
1272 ** Read a decimal number from the terminal. Set cmd to the non-digit which
1273 ** terminates the number.
1276 int number(char *cmd
)
1280 i
= 0; ch
= otty
.c_cc
[VKILL
];
1284 i
= i
*10 + ch
- '0';
1285 else if (ch
== otty
.c_cc
[VKILL
])
1295 void do_shell (char *filename
)
1306 ttyin (cmdbuf
, sizeof(cmdbuf
)-2, '!');
1307 if (expand (shell_line
, cmdbuf
)) {
1309 promptlen
= xprintf ("!%s", shell_line
);
1316 execute (filename
, shell
, shell
, "-c", shell_line
, 0);
1320 ** Search for nth ocurrence of regular expression contained in buf in the file
1323 void search(char buf
[], FILE *file
, register int n
)
1325 long startline
= Ftell (file
);
1326 register long line1
= startline
;
1327 register long line2
= startline
;
1328 register long line3
= startline
;
1329 register int lncount
;
1330 int saveln
, rv
, re_exec();
1331 char *s
, *re_comp();
1333 context
.line
= saveln
= Currline
;
1334 context
.chrctr
= startline
;
1336 if ((s
= re_comp (buf
)) != 0)
1338 while (!feof (file
)) {
1341 line1
= Ftell (file
);
1344 if ((rv
= re_exec (Line
)) == 1) {
1346 if (lncount
> 3 || (lncount
> 1 && no_intty
))
1351 pr("...skipping\n");
1354 Currline
-= (lncount
>= 3 ? 3 : lncount
);
1355 Fseek (file
, line3
);
1380 } else if (rv
== -1)
1381 error ("Regular expression botch");
1386 /* No longer in libc 4.5.8. . . */
1387 file
->_flags
&= ~STDIO_S_EOF_SEEN
; /* why doesn't fseek do this ??!!??! */
1390 Fseek (file
, startline
);
1393 pr ("\nPattern not found\n");
1396 error ("Pattern not found");
1401 void execute (char * filename
, char * cmd
, ...)
1412 for (n
= 10; (id
= fork ()) < 0 && n
> 0; n
--)
1417 open("/dev/tty", 0);
1420 va_start(argp
, cmd
);
1422 arg
= va_arg(argp
, char *);
1426 arg
= va_arg(argp
, char *);
1428 va_end(argp
); /* balance {}'s for some UNIX's */
1430 args
= alloca(sizeof(char *) * (argcount
+ 1));
1431 args
[argcount
] = NULL
;
1433 va_start(argp
, cmd
);
1434 arg
= va_arg(argp
, char *);
1437 args
[argcount
] = arg
;
1439 arg
= va_arg(argp
, char *);
1441 va_end(argp
); /* balance {}'s for some UNIX's */
1444 errwrite("exec failed\n");
1448 signal (SIGINT
, SIG_IGN
);
1449 signal (SIGQUIT
, SIG_IGN
);
1451 signal(SIGTSTP
, SIG_DFL
);
1452 while (wait(0) > 0);
1453 signal (SIGINT
, end_it
);
1454 signal (SIGQUIT
, onquit
);
1456 signal(SIGTSTP
, onsusp
);
1458 errwrite("can't fork\n");
1460 pr ("------------------------\n");
1464 ** Skip n lines in the file f
1467 void skiplns (register int n
, register FILE *f
)
1472 while ((c
= Getc (f
)) != '\n')
1481 ** Skip nskip files in the file list (from the command line). Nskip may be
1485 void skipf (register int nskip
)
1487 if (nskip
== 0) return;
1489 if (fnum
+ nskip
> nfiles
- 1)
1490 nskip
= nfiles
- fnum
- 1;
1497 pr ("\n...Skipping ");
1501 pr ("...Skipping ");
1502 pr (nskip
> 0 ? "to file " : "back to file ");
1511 /*----------------------------- Terminal I/O -------------------------------*/
1523 no_tty
= tcgetattr(fileno(stdout
), &otty
);
1525 docrterase
= (otty
.c_cc
[VERASE
] != 255);
1526 docrtkill
= (otty
.c_cc
[VKILL
] != 255);
1531 * Wait until we're in the foreground before we save the
1532 * the terminal modes.
1534 if (ioctl(fileno(stdout
), TIOCGPGRP
, &tgrp
) < 0) {
1535 perror("TIOCGPGRP");
1538 if (tgrp
!= getpgrp(0)) {
1544 if ((term
= getenv("TERM")) == 0) {
1547 setupterm(term
, 1, &ret
);
1553 if (ioctl(fileno(stdout
), TIOCGWINSZ
, &win
) < 0) {
1555 Lpp
= tigetnum("lines");
1556 Mcol
= tigetnum("cols");
1559 if ((Lpp
= win
.ws_row
) == 0)
1560 Lpp
= tigetnum("lines");
1561 if ((Mcol
= win
.ws_col
) == 0)
1562 Mcol
= tigetnum("cols");
1565 if ((Lpp
<= 0) || tigetflag("hc")) {
1566 hard
++; /* Hard copy terminal */
1570 if (tigetflag("xenl"))
1571 eatnl
++; /* Eat newline at last column + 1; dec, concept */
1575 if (tailequ (fnames
[0], "page"))
1577 Wrap
= tigetflag("am");
1578 bad_so
= tigetflag ("xhp");
1579 eraseln
= tigetstr("el");
1580 Clear
= tigetstr("clear");
1581 Senter
= tigetstr("smso");
1582 Sexit
= tigetstr("rmso");
1583 if ((soglitch
= tigetnum("xmc")) < 0)
1587 * Set up for underlining: some terminals don't need it;
1588 * others have start/stop sequences, still others have an
1589 * underline char sequence which is assumed to move the
1590 * cursor forward one character. If underline sequence
1591 * isn't available, settle for standout sequence.
1594 if (tigetflag("ul") || tigetflag("os"))
1596 if ((chUL
= tigetstr("uc")) == NULL
)
1598 if (((ULenter
= tigetstr("smul")) == NULL
||
1599 (ULexit
= tigetstr("rmul")) == NULL
) && !*chUL
) {
1600 if ((ULenter
= Senter
) == NULL
|| (ULexit
= Sexit
) == NULL
) {
1604 ulglitch
= soglitch
;
1609 if ((padstr
= tigetstr("pad")) != NULL
)
1611 Home
= tigetstr("home");
1612 if (Home
== 0 || *Home
== '\0')
1614 if ((cursorm
= tigetstr("cup")) != NULL
) {
1615 strcpy(cursorhome
, (const char *)tparm(cursorm
, 0, 0));
1619 EodClr
= tigetstr("ed");
1620 if ((chBS
= tigetstr("cub1")) == NULL
)
1624 if ((shell
= getenv("SHELL")) == NULL
)
1627 no_intty
= tcgetattr(fileno(stdin
), &otty
);
1628 tcgetattr(fileno(stderr
), &otty
);
1630 slow_tty
= (otty
.c_cflag
& CBAUD
) < B1200
;
1631 hardtabs
= (otty
.c_oflag
& TABDLY
) != XTABS
;
1633 otty
.c_lflag
&= ~(ICANON
|ECHO
);
1634 otty
.c_cc
[VMIN
] = 1;
1635 otty
.c_cc
[VTIME
] = 0;
1645 if (read (2, &ch
, 1) <= 0) {
1649 ch
= otty
.c_cc
[VKILL
];
1654 static char *BS
= "\b";
1655 static char *BSB
= "\b \b";
1656 static char *CARAT
= "^";
1657 #define ERASEONECHAR \
1663 void ttyin (char buf
[], register int nmax
, char pchar
)
1665 register char *sptr
;
1667 register int slash
= 0;
1673 while (sptr
- buf
< nmax
) {
1674 if (promptlen
> maxlen
) maxlen
= promptlen
;
1679 else if ((ch
== otty
.c_cc
[VERASE
]) && !slash
) {
1684 if ((*sptr
< ' ' && *sptr
!= '\n') || *sptr
== RUBOUT
) {
1691 if (!eraseln
) promptlen
= maxlen
;
1692 longjmp (restore
, 1);
1695 else if ((ch
== otty
.c_cc
[VKILL
]) && !slash
) {
1707 while (promptlen
-- > 1)
1715 if (slash
&& (ch
== otty
.c_cc
[VKILL
] || ch
== otty
.c_cc
[VERASE
])) {
1722 if ((ch
< ' ' && ch
!= '\n' && ch
!= ESC
) || ch
== RUBOUT
) {
1723 ch
+= ch
== RUBOUT
? -0100 : 0100;
1728 if (ch
!= '\n' && ch
!= ESC
) {
1736 if (!eraseln
) promptlen
= maxlen
;
1737 if (sptr
- buf
>= nmax
- 1)
1738 error ("Line too long");
1741 int expand (char *outbuf
, char *inbuf
)
1743 register char *instr
;
1744 register char *outstr
;
1751 while ((ch
= *instr
++) != '\0')
1755 strcpy (outstr
, fnames
[fnum
]);
1756 outstr
+= strlen (fnames
[fnum
]);
1764 error ("No previous command to substitute for");
1765 strcpy (outstr
, shell_line
);
1766 outstr
+= strlen (shell_line
);
1770 if (*instr
== '%' || *instr
== '!') {
1771 *outstr
++ = *instr
++;
1778 strcpy (outbuf
, temp
);
1782 void show (register char ch
)
1786 if ((ch
< ' ' && ch
!= '\n' && ch
!= ESC
) || ch
== RUBOUT
) {
1787 ch
+= ch
== RUBOUT
? -0100 : 0100;
1796 void errwrite (char *txt
)
1798 write (fileno(stderr
), txt
, strlen(txt
));
1801 void errwrite1 (char *sym
)
1803 write (fileno(stderr
), sym
, 1);
1806 void error (char *mess
)
1812 promptlen
+= strlen (mess
);
1813 if (Senter
&& Sexit
) {
1822 longjmp (restore
, 1);
1828 otty
.c_lflag
&= ~(ICANON
|ECHO
);
1829 otty
.c_cc
[VMIN
] = 1; /* read at least 1 char */
1830 otty
.c_cc
[VTIME
] = 0; /* no timeout */
1831 stty(fileno(stderr
), &otty
);
1834 int ourputch(int ch
) {
1835 return putc(ch
, stdout
);
1843 tputs(ULexit
, 1, ourputch
);
1847 otty
.c_lflag
|= ICANON
|ECHO
;
1848 otty
.c_cc
[VMIN
] = savetty0
.c_cc
[VMIN
];
1849 otty
.c_cc
[VTIME
] = savetty0
.c_cc
[VTIME
];
1850 stty(fileno(stderr
), &savetty0
);
1853 void rdline (register FILE *f
)
1859 while ((c
= Getc (f
)) != '\n' && c
!= EOF
&& p
- Line
< LINSIZ
- 1)
1866 /* Come here when we get a suspend signal from the terminal */
1870 sigset_t signals
, oldmask
;
1872 /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
1873 signal(SIGTTOU
, SIG_IGN
);
1876 signal(SIGTTOU
, SIG_DFL
);
1877 /* Send the TSTP signal to suspend our process group */
1878 signal(SIGTSTP
, SIG_DFL
);
1880 /* unblock SIGTSTP or we won't be able to suspend ourself */
1881 sigemptyset(&signals
);
1882 sigaddset(&signals
, SIGTSTP
);
1883 sigprocmask(SIG_UNBLOCK
, &signals
, &oldmask
);
1886 /* Pause for station break */
1888 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
1891 signal (SIGTSTP
, onsusp
);
1894 longjmp (restore
, 1);