]>
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
29 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
30 - added Native Language Support
31 1999-03-19 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
32 - more nls translatable strings
33 1999-05-09 aeb - applied a RedHat patch (setjmp->sigsetjmp); without it
34 a second ^Z would fail.
35 1999-05-09 aeb - undone Kars' work, so that more works without
36 libcurses (and hence can be in /bin with libcurses being in /usr/lib
37 which may not be mounted). However, when termcap is not present curses
44 #include <stdlib.h> /* for alloca() */
45 #include <stdarg.h> /* for va_start() etc */
46 #include <sys/param.h>
52 #include <sys/ioctl.h>
60 #define _REGEX_RE_COMP
64 /* #define MOREHELPFILE "/usr/lib/more.help" */
65 #define VI "vi" /* found on the user's path */
67 #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m))
68 #define Ftell(f) file_pos
69 #define Fseek(f,off) (file_pos=off,fseek(f,off,0))
70 #define Getc(f) (++file_pos, getc(f))
71 #define Ungetc(c,f) (--file_pos, ungetc(c,f))
73 #define stty(fd,argp) tcsetattr(fd,TCSANOW,argp)
75 /* some function declarations */
82 void error (char *mess
);
83 void do_shell (char *filename
);
84 int colon (char *filename
, int cmd
, int nlines
);
85 int expand (char **outbuf
, char *inbuf
);
86 void argscan(char *s
,char *argv0
);
87 void rdline (register FILE *f
);
88 void copy_file(register FILE *f
);
89 void search(char buf
[], FILE *file
, register int n
);
90 void skipf (register int nskip
);
91 void skiplns(register int n
, register FILE *f
);
92 void screen (register FILE *f
, register int num_lines
);
93 int command (char *filename
, register FILE *f
);
94 void erasep (register int col
);
95 void show (register char ch
);
100 void ttyin (char buf
[], register int nmax
, char pchar
);
101 int number(char *cmd
);
103 int get_line(register FILE *f
, int *length
);
104 void prbuf (register char *s
, register int n
);
105 int xprintf (char *fmt
, ...);
106 void execute (char *filename
, char *cmd
, ...);
107 void errwrite (char *txt
);
108 void errwrite1 (char *sym
);
109 FILE *checkf (char *, int *);
113 #define ctrl(letter) (letter & 077)
114 #define RUBOUT '\177'
118 struct termios otty
, savetty0
;
119 long file_pos
, file_size
;
120 int fnum
, no_intty
, no_tty
, slow_tty
;
122 void onquit(int), onsusp(int), chgwinsz(int), end_it(int);
123 int nscroll
= 11; /* Number of lines scrolled by 'd' */
124 int fold_opt
= 1; /* Fold long lines */
125 int stop_opt
= 1; /* Stop after form feeds */
126 int ssp_opt
= 0; /* Suppress white space */
127 int ul_opt
= 1; /* Underline as best we can */
129 int Currline
; /* Line we are currently at */
135 int bad_so
; /* True if overwriting does not turn off standout */
136 int inwait
, Pause
, errors
;
137 int within
; /* true if we are within a file,
138 false if we are between files */
139 int hard
, dumb
, noscroll
, hardtabs
, clreol
, eatnl
;
140 int catch_susp
; /* We should catch the SIGTSTP signal */
141 char **fnames
; /* The list of file names */
142 int nfiles
; /* Number of files left to process */
143 char *shell
; /* The name of the shell to use */
144 int shellp
; /* A previous shell command exists */
146 char Line
[LINSIZ
+2]; /* Line buffer */
147 int Lpp
= 24; /* lines per page */
148 char *Clear
; /* clear screen */
149 char *eraseln
; /* erase line */
150 char *Senter
, *Sexit
;/* enter and exit standout mode */
151 char *ULenter
, *ULexit
; /* enter and exit underline mode */
152 char *chUL
; /* underline character */
153 char *chBS
; /* backspace character */
154 char *Home
; /* go to home */
155 char *cursorm
; /* cursor movement */
156 char cursorhome
[40]; /* contains cursor movement to home */
157 char *EodClr
; /* clear rest of screen */
158 int Mcol
= 80; /* number of columns */
159 int Wrap
= 1; /* set if automargins */
160 int soglitch
; /* terminal has standout mode glitch */
161 int ulglitch
; /* terminal has underline mode glitch */
162 int pstate
= 0; /* current UL state */
163 static int magic(FILE *, char *);
166 } context
, screen_start
;
167 extern char PC
; /* pad character */
180 #include <term.h> /* include after <curses.h> */
183 my_putstring(char *s
) {
188 my_setupterm(const char *term
, int fildes
, int *errret
) {
189 setupterm(term
, fildes
, errret
);
193 my_tgetnum(char *s
, char *ss
) {
198 my_tgetflag(char *s
, char *ss
) {
199 return tigetflag(ss
);
203 my_tgetstr(char *s
, char *ss
) {
208 my_tgoto(const char *cap
, int col
, int row
) {
209 return tparm(cap
, col
, row
);
212 #else /* no CURSES */
215 char termbuffer
[4096];
217 char *strbuf
= termbuffer
;
220 my_putstring(char *s
) {
221 tputs (s
, 1, putchar
);
225 my_setupterm(const char *term
, int fildes
, int *errret
) {
226 *errret
= tgetent(tcbuffer
, term
);
230 my_tgetnum(char *s
, char *ss
) {
235 my_tgetflag(char *s
, char *ss
) {
240 my_tgetstr(char *s
, char *ss
) {
241 return tgetstr(s
, &strbuf
);
245 my_tgoto(const char *cap
, int col
, int row
) {
246 return tgoto(cap
, col
, row
);
250 #endif /* USE_CURSES */
260 char *p
= strrchr(s
, '/');
262 _("usage: %s [-dflpcsu] [+linenum | +/pattern] name1 name2 ...\n"),
266 int main(int argc
, char **argv
) {
279 setlocale(LC_ALL
, "");
280 bindtextdomain(PACKAGE
, LOCALEDIR
);
283 /* avoid gcc complaints about register variables that
284 may be clobbered by a longjmp, by forcing our variables here
285 to be non-register */
286 Fdummy(&f
); idummy(&left
); idummy(&prnames
);
287 idummy(&initopt
); idummy(&srchopt
); idummy(&initline
);
291 setlocale(LC_ALL
, "");
296 if((s
= getenv("MORE")) != NULL
) argscan(s
,argv
[0]);
297 while (--nfiles
> 0) {
298 if ((ch
= (*++fnames
)[0]) == '-') {
299 argscan(*fnames
+1,argv
[0]);
301 else if (ch
== '+') {
305 for (++s
, p
= initbuf
; p
< initbuf
+ 79 && *s
!= '\0';)
311 for (initline
= 0; *s
!= '\0'; s
++)
313 initline
= initline
*10 + *s
-'0';
319 /* allow clreol only if Home and eraseln and EodClr strings are
320 * defined, and in that case, make sure we are in noscroll mode
324 if((Home
== NULL
) || (*Home
== '\0') ||
325 (eraseln
== NULL
) || (*eraseln
== '\0') ||
326 (EodClr
== NULL
) || (*EodClr
== '\0') )
331 dlines
= Lpp
- (noscroll
? 1 : 2);
335 if (!no_intty
&& nfiles
== 0) {
342 signal(SIGQUIT
, onquit
);
343 signal(SIGINT
, end_it
);
345 signal(SIGWINCH
, chgwinsz
);
347 if (signal (SIGTSTP
, SIG_IGN
) == SIG_DFL
) {
348 signal(SIGTSTP
, onsusp
);
351 stty (fileno(stderr
), &otty
);
357 if ((ch
= Getc (f
)) == '\f')
361 if (noscroll
&& (ch
!= EOF
)) {
370 search (initbuf
, stdin
, 1);
375 skiplns (initline
, stdin
);
376 screen (stdin
, left
);
383 while (fnum
< nfiles
) {
384 if ((f
= checkf (fnames
[fnum
], &clearit
)) != NULL
) {
385 context
.line
= context
.chrctr
= 0;
387 if (firstf
) sigsetjmp (restore
, 1);
391 search (initbuf
, f
, 1);
396 skiplns (initline
, f
);
398 else if (fnum
< nfiles
&& !no_tty
) {
399 sigsetjmp (restore
, 1);
400 left
= command (fnames
[fnum
], f
);
403 if ((noscroll
|| clearit
) && (file_size
!= LONG_MAX
)) {
414 pr("::::::::::::::");
418 if(clreol
) cleareol();
419 xprintf("%s\n", fnames
[fnum
]);
420 if(clreol
) cleareol();
421 xprintf("::::::::::::::\n");
433 sigsetjmp (restore
, 1);
436 screen_start
.line
= screen_start
.chrctr
= 0L;
437 context
.line
= context
.chrctr
= 0L;
446 void argscan(char *s
, char *argv0
) {
451 case '0': case '1': case '2':
452 case '3': case '4': case '5':
453 case '6': case '7': case '8':
459 dlines
= dlines
*10 + *s
- '0';
482 case '-': case ' ': case '\t':
486 fputs(": unknown option \"-",stderr
);
488 fputs("\"\n",stderr
);
499 ** Check whether the file named by fs is an ASCII file which the user may
500 ** access. If it is, return the opened file. Otherwise return NULL.
504 checkf (fs
, clearfirst
)
512 if (stat (fs
, &stbuf
) == -1) {
513 (void)fflush(stdout
);
517 return((FILE *)NULL
);
519 if ((stbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
520 xprintf(_("\n*** %s: directory ***\n\n"), fs
);
521 return((FILE *)NULL
);
523 if ((f
= Fopen(fs
, "r")) == NULL
) {
524 (void)fflush(stdout
);
526 return((FILE *)NULL
);
529 return((FILE *)NULL
);
531 *clearfirst
= c
== '\f';
533 if ((file_size
= stbuf
.st_size
) == 0)
534 file_size
= LONG_MAX
;
540 * check for file magic numbers. This code would best be shared with
541 * the file(1) program or, perhaps, more should not try and be so smart?
550 if (fread(twobytes
, 2, 1, f
) == 1) {
551 switch(twobytes
[0] + (twobytes
[1]<<8)) {
552 case OMAGIC
: /* 0407 */
553 case NMAGIC
: /* 0410 */
554 case ZMAGIC
: /* 0413 */
558 case 0x457f: /* simple ELF detection */
559 xprintf(_("\n******** %s: Not a text file ********\n\n"), fs
);
564 (void)fseek(f
, 0L, SEEK_SET
); /* rewind() not necessary */
569 ** Print out the contents of the file f, one screenful at a time.
574 void screen (register FILE *f
, register int num_lines
)
578 int length
; /* length of current line */
579 static int prev_len
= 1; /* length of previous line */
582 while (num_lines
> 0 && !Pause
) {
583 if ((nchars
= get_line (f
, &length
)) == EOF
)
589 if (ssp_opt
&& length
== 0 && prev_len
== 0)
592 if (bad_so
|| ((Senter
&& *Senter
== ' ') && (promptlen
> 0)))
594 /* must clear before drawing line since tabs on some terminals
595 * do not erase what they tab over.
599 prbuf (Line
, length
);
600 if (nchars
< promptlen
)
601 erasep (nchars
); /* erasep () sets promptlen to 0 */
605 * cleareol(); * must clear again in case we wrapped *
607 if (nchars
< Mcol
|| !fold_opt
)
608 prbuf("\n", 1); /* will turn off UL if necessary */
614 my_putstring (ULexit
);
618 if ((c
= Getc(f
)) == EOF
)
628 sigsetjmp (restore
, 1);
629 Pause
= 0; startup
= 0;
630 if ((num_lines
= command (NULL
, f
)) == 0)
632 if (hard
&& promptlen
> 0)
634 if (noscroll
&& num_lines
>= dlines
)
641 screen_start
.line
= Currline
;
642 screen_start
.chrctr
= Ftell (f
);
647 ** Come here if a quit signal is received
650 void onquit(int dummy
) {
651 signal(SIGQUIT
, SIG_IGN
);
655 signal(SIGQUIT
, onquit
);
656 siglongjmp (restore
, 1);
661 else if (!dum_opt
&& notell
) {
662 char *s
= _("[Use q or Q to quit]");
664 promptlen
+= strlen(s
);
667 signal(SIGQUIT
, onquit
);
671 ** Come here if a signal for a window size change is received
675 void chgwinsz(int dummy
) {
678 (void) signal(SIGWINCH
, SIG_IGN
);
679 if (ioctl(fileno(stdout
), TIOCGWINSZ
, &win
) != -1) {
680 if (win
.ws_row
!= 0) {
685 dlines
= Lpp
- (noscroll
? 1 : 2);
690 (void) signal(SIGWINCH
, chgwinsz
);
695 ** Clean up terminal state and exit. Also come here if interrupt signal received
698 void end_it (int dummy
) {
705 else if (!clreol
&& (promptlen
> 0)) {
714 void copy_file(register FILE *f
) {
717 while ((c
= getc(f
)) != EOF
)
721 /* Simplified printf function */
723 int xprintf (char *fmt
, ...) {
731 while ((ch
= *fmt
++) != '%') {
739 ccount
+= printd (va_arg(ap
, int));
742 ccount
+= pr (va_arg(ap
, char *));
760 ** Print an integer as a string of decimal digits,
761 ** returning the length of the print representation.
769 nchars
= 1 + printd(a
);
772 putchar (n
% 10 + '0');
776 /* Put the print representation of an integer into a string */
779 static void Sprintf (int n
) {
784 *sptr
++ = n
% 10 + '0';
787 static void scanstr (int n
, char *str
)
794 #define ringbell() errwrite("\007");
809 /* See whether the last component of the path name "path" is equal to the
813 static int tailequ (char *path
, register char *string
)
817 tail
= path
+ strlen(path
);
818 while (--tail
>= path
)
822 while (*tail
++ == *string
++)
828 static void prompt (char *filename
)
832 else if (promptlen
> 0)
836 if (Senter
&& Sexit
) {
837 my_putstring (Senter
);
838 promptlen
+= (2 * soglitch
);
842 promptlen
+= pr(_("--More--"));
843 if (filename
!= NULL
) {
844 promptlen
+= xprintf (_("(Next file: %s)"), filename
);
845 } else if (!no_intty
) {
846 promptlen
+= xprintf ("(%d%%)",
847 (int)((file_pos
* 100) / file_size
));
850 promptlen
+= pr(_("[Press space to continue, 'q' to quit.]"));
853 my_putstring (Sexit
);
864 ** Get a logical line
867 int get_line(register FILE *f
, int *length
)
877 if (colflg
&& c
== '\n') {
881 while (p
< &Line
[LINSIZ
- 1]) {
897 if (c
== '\033') { /* ESC */
899 while (c
> ' ' && c
< '0' && p
< &Line
[LINSIZ
- 1]) {
903 if (c
>= '0' && c
< '\177' && p
< &Line
[LINSIZ
- 1]) {
911 if (!hardtabs
|| (column
< promptlen
&& !hard
)) {
912 if (hardtabs
&& eraseln
&& !dumb
) {
913 column
= 1 + (column
| 7);
914 my_putstring (eraseln
);
918 for (--p
; p
< &Line
[LINSIZ
- 1];) {
920 if ((++column
& 7) == 0)
923 if (column
>= promptlen
) promptlen
= 0;
927 column
= 1 + (column
| 7);
928 } else if (c
== '\b' && column
> 0) {
930 } else if (c
== '\r') {
939 } else if (c
== '\f' && stop_opt
) {
944 } else if (c
== EOF
) {
950 char ch
[2]; /* for mblen() */
954 if (mblen(ch
, 1) <= 0) { /* multibyte, maybe 2 columns */
955 if (column
== Mcol
-1 && fold_opt
) {
962 } else if (c
& 0x80) { /* maybe SJIS KANA, or utf-8 ? */
964 } else if (isprint(c
))
971 if (column
>= Mcol
&& fold_opt
)
975 if (column
>= Mcol
&& Mcol
> 0) {
980 colflg
= column
== Mcol
&& fold_opt
;
981 if (colflg
&& eatnl
&& Wrap
) {
982 *p
++ = '\n'; /* simulate normal wrap */
990 ** Erase the rest of the prompt, assuming we are starting at column col.
993 void erasep (register int col
)
1004 if (!dumb
&& eraseln
)
1005 my_putstring (eraseln
);
1007 for (col
= promptlen
- col
; col
> 0; col
--)
1014 ** Erase the current line entirely
1020 if (!eraseln
|| dumb
)
1025 * force clear to end of line
1029 my_putstring(eraseln
);
1034 my_putstring(EodClr
);
1038 ** Print string and return number of characters
1046 for (s
= s1
; (c
= *s
++) != 0; )
1048 return (int) (s
- s1
- 1);
1052 /* Print a buffer of n characters */
1054 void prbuf (register char *s
, register int n
)
1056 register char c
; /* next output character */
1057 register int state
; /* next output char's UL state */
1058 #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_')))
1064 if (*s
== ' ' && pstate
== 0 && ulglitch
&& wouldul(s
+1, n
-1)) {
1068 if ((state
= wouldul(s
, n
)) != 0) {
1069 c
= (*s
== '_')? s
[2] : *s
;
1074 if (state
!= pstate
) {
1075 if (c
== ' ' && state
== 0 && ulglitch
&& wouldul(s
, n
-1))
1078 my_putstring(state
? ULenter
: ULexit
);
1080 if (c
!= ' ' || pstate
== 0 || state
!= 0 || ulglitch
== 0)
1082 if (state
&& *chUL
) {
1096 if (Clear
&& !hard
) {
1097 my_putstring(Clear
);
1099 /* Put out carriage return so that system doesn't
1100 ** get confused by escape sequences when expanding tabs
1108 * Go to home position
1116 static int lastcmd
, lastarg
, lastp
;
1117 static int lastcolon
;
1118 char shell_line
[1000];
1121 ** Read a command and do it. A command consists of an optional integer
1122 ** argument followed by the command character. Return the number of lines
1123 ** to display in the next screenful. If there is nothing more to display
1124 ** in the current file, zero is returned.
1127 int command (char *filename
, register FILE *f
)
1129 register int nlines
;
1130 register int retval
= 0;
1135 char comchar
, cmdbuf
[80];
1137 #define ret(val) retval=val;done++;break
1145 nlines
= number (&comchar
);
1146 lastp
= colonch
= 0;
1147 if (comchar
== '.') { /* Repeat last command */
1152 colonch
= lastcolon
;
1156 if ((cc_t
) comchar
== otty
.c_cc
[VERASE
]) {
1163 retval
= colon (filename
, colonch
, nlines
);
1170 register int initline
;
1177 if (nlines
== 0) nlines
++;
1184 xprintf (_("...back %d page"), nlines
);
1194 initline
= Currline
- dlines
* (nlines
+ 1);
1197 if (initline
< 0) initline
= 0;
1199 Currline
= 0; /* skiplns() will make Currline correct */
1200 skiplns(initline
, f
);
1210 if (nlines
== 0) nlines
= dlines
;
1211 else if (comchar
== 'z') dlines
= nlines
;
1215 if (nlines
!= 0) nscroll
= nlines
;
1222 if (nlines
== 0) nlines
++;
1230 xprintf (_("...skipping %d line"), nlines
);
1240 while (nlines
> 0) {
1241 while ((c
= Getc (f
)) != '\n')
1260 Fseek (f
, screen_start
.chrctr
);
1261 Currline
= screen_start
.line
;
1271 pr (_("\n***Back***\n\n"));
1272 Fseek (f
, context
.chrctr
);
1273 Currline
= context
.line
;
1282 promptlen
= printd (Currline
);
1288 if (nlines
== 0) nlines
++;
1295 search (NULL
, f
, nlines
); /* Use previous r.e. */
1298 ttyin (cmdbuf
, sizeof(cmdbuf
)-2, '/');
1300 search (cmdbuf
, f
, nlines
);
1304 do_shell (filename
);
1311 char hlpfile
[sizeof(MOREHELPFILE
)+4];
1313 lang
= getenv("LANGUAGE");
1314 if (!lang
|| *lang
== '\0')
1315 lang
= setlocale(LC_MESSAGES
, "");
1316 if (!lang
|| *lang
== '\0')
1317 lang
= getenv("LANG");
1318 if (lang
&& strlen(lang
) > 1) {
1319 strcpy(hlpfile
, MOREHELPFILE
);
1320 strcat(hlpfile
, ".");
1321 strncat(hlpfile
, lang
, 2);
1322 helpf
= fopen (hlpfile
, "r");
1326 helpf
= fopen (MOREHELPFILE
, "r");
1328 error (_("Can't open help file"));
1329 if (noscroll
) doclear ();
1334 case 'v': /* This case should go right before default */
1338 editor
= getenv("VISUAL");
1339 if (editor
== NULL
|| *editor
== '\0')
1340 editor
= getenv("EDITOR");
1341 if (editor
== NULL
|| *editor
== '\0')
1346 scanstr (Currline
- dlines
<= 0 ? 1
1347 : Currline
- (dlines
+ 1) / 2, &cmdbuf
[1]);
1348 pr (editor
); putchar (' ');
1349 pr (cmdbuf
); putchar (' '); pr (fnames
[fnum
]);
1350 execute (filename
, editor
, editor
, cmdbuf
, fnames
[fnum
], 0);
1356 if (Senter
&& Sexit
) {
1357 my_putstring (Senter
);
1358 promptlen
= pr (_("[Press 'h' for instructions.]")) + (2 * soglitch
);
1359 my_putstring (Sexit
);
1362 promptlen
= pr (_("[Press 'h' for instructions.]"));
1381 * Execute a colon-prefixed command.
1382 * Returns <0 if not a command that should cause
1383 * more of the file to be printed.
1386 int colon (char *filename
, int cmd
, int nlines
) {
1396 promptlen
= xprintf (_("\"%s\" line %d"), fnames
[fnum
], Currline
);
1398 promptlen
= xprintf (_("[Not a file] line %d"), Currline
);
1403 if (fnum
>= nfiles
- 1)
1423 do_shell (filename
);
1435 ** Read a decimal number from the terminal. Set cmd to the non-digit which
1436 ** terminates the number.
1439 int number(char *cmd
)
1443 i
= 0; ch
= otty
.c_cc
[VKILL
];
1447 i
= i
*10 + ch
- '0';
1448 else if ((cc_t
) ch
== otty
.c_cc
[VKILL
])
1458 void do_shell (char *filename
)
1471 ttyin (cmdbuf
, sizeof(cmdbuf
)-2, '!');
1473 rc
= expand (&expanded
, cmdbuf
);
1475 if (strlen(expanded
) < sizeof(shell_line
))
1476 strcpy(shell_line
, expanded
);
1482 errwrite(_(" Overflow\n"));
1485 } else if (rc
> 0) {
1487 promptlen
= xprintf ("!%s", shell_line
);
1494 execute (filename
, shell
, shell
, "-c", shell_line
, 0);
1498 ** Search for nth ocurrence of regular expression contained in buf in the file
1501 void search(char buf
[], FILE *file
, register int n
)
1503 long startline
= Ftell (file
);
1504 register long line1
= startline
;
1505 register long line2
= startline
;
1506 register long line3
= startline
;
1507 register int lncount
;
1511 context
.line
= saveln
= Currline
;
1512 context
.chrctr
= startline
;
1514 if ((s
= re_comp (buf
)) != 0)
1516 while (!feof (file
)) {
1519 line1
= Ftell (file
);
1522 if ((rv
= re_exec (Line
)) == 1) {
1524 if (lncount
> 3 || (lncount
> 1 && no_intty
))
1529 pr(_("...skipping\n"));
1532 Currline
-= (lncount
>= 3 ? 3 : lncount
);
1533 Fseek (file
, line3
);
1558 } else if (rv
== -1)
1559 error (_("Regular expression botch"));
1564 /* No longer in libc 4.5.8. . . */
1565 file
->_flags
&= ~STDIO_S_EOF_SEEN
; /* why doesn't fseek do this ??!!??! */
1568 Fseek (file
, startline
);
1571 pr (_("\nPattern not found\n"));
1574 error (_("Pattern not found"));
1579 void execute (char * filename
, char * cmd
, ...)
1590 for (n
= 10; (id
= fork ()) < 0 && n
> 0; n
--)
1595 open("/dev/tty", 0);
1598 va_start(argp
, cmd
);
1599 arg
= va_arg(argp
, char *);
1603 arg
= va_arg(argp
, char *);
1607 args
= alloca(sizeof(char *) * (argcount
+ 1));
1608 args
[argcount
] = NULL
;
1610 va_start(argp
, cmd
);
1611 arg
= va_arg(argp
, char *);
1614 args
[argcount
] = arg
;
1616 arg
= va_arg(argp
, char *);
1621 errwrite(_("exec failed\n"));
1625 signal (SIGINT
, SIG_IGN
);
1626 signal (SIGQUIT
, SIG_IGN
);
1628 signal(SIGTSTP
, SIG_DFL
);
1629 while (wait(0) > 0);
1630 signal (SIGINT
, end_it
);
1631 signal (SIGQUIT
, onquit
);
1633 signal(SIGTSTP
, onsusp
);
1635 errwrite(_("can't fork\n"));
1637 pr ("------------------------\n");
1641 ** Skip n lines in the file f
1644 void skiplns (register int n
, register FILE *f
)
1649 while ((c
= Getc (f
)) != '\n')
1658 ** Skip nskip files in the file list (from the command line). Nskip may be
1662 void skipf (register int nskip
)
1664 if (nskip
== 0) return;
1666 if (fnum
+ nskip
> nfiles
- 1)
1667 nskip
= nfiles
- fnum
- 1;
1674 pr (_("\n...Skipping "));
1678 pr (_("...Skipping "));
1679 pr (nskip
> 0 ? _("to file ") : _("back to file "));
1688 /*----------------------------- Terminal I/O -------------------------------*/
1700 no_tty
= tcgetattr(fileno(stdout
), &otty
);
1702 docrterase
= (otty
.c_cc
[VERASE
] != 255);
1703 docrtkill
= (otty
.c_cc
[VKILL
] != 255);
1708 * Wait until we're in the foreground before we save the
1709 * the terminal modes.
1711 if (ioctl(fileno(stdout
), TIOCGPGRP
, &tgrp
) < 0) {
1712 perror("TIOCGPGRP");
1715 if (tgrp
!= getpgrp(0)) {
1721 if ((term
= getenv("TERM")) == 0) {
1724 my_setupterm(term
, 1, &ret
);
1730 if (ioctl(fileno(stdout
), TIOCGWINSZ
, &win
) < 0) {
1732 Lpp
= my_tgetnum("li","lines");
1733 Mcol
= my_tgetnum("co","cols");
1736 if ((Lpp
= win
.ws_row
) == 0)
1737 Lpp
= my_tgetnum("li","lines");
1738 if ((Mcol
= win
.ws_col
) == 0)
1739 Mcol
= my_tgetnum("co","cols");
1742 if ((Lpp
<= 0) || my_tgetflag("hc","hc")) {
1743 hard
++; /* Hard copy terminal */
1747 if (my_tgetflag("xn","xenl"))
1748 eatnl
++; /* Eat newline at last column + 1; dec, concept */
1752 if (tailequ (fnames
[0], "page"))
1754 Wrap
= my_tgetflag("am","am");
1755 bad_so
= my_tgetflag ("xs","xhp");
1756 eraseln
= my_tgetstr("ce","el");
1757 Clear
= my_tgetstr("cl","clear");
1758 Senter
= my_tgetstr("so","smso");
1759 Sexit
= my_tgetstr("se","rmso");
1760 if ((soglitch
= my_tgetnum("sg","xmc")) < 0)
1764 * Set up for underlining: some terminals don't need it;
1765 * others have start/stop sequences, still others have an
1766 * underline char sequence which is assumed to move the
1767 * cursor forward one character. If underline sequence
1768 * isn't available, settle for standout sequence.
1771 if (my_tgetflag("ul","ul") || my_tgetflag("os","os"))
1773 if ((chUL
= my_tgetstr("uc","uc")) == NULL
)
1775 if (((ULenter
= my_tgetstr("us","smul")) == NULL
||
1776 (ULexit
= my_tgetstr("ue","rmul")) == NULL
) && !*chUL
) {
1777 if ((ULenter
= Senter
) == NULL
|| (ULexit
= Sexit
) == NULL
) {
1781 ulglitch
= soglitch
;
1786 if ((padstr
= my_tgetstr("pc","pad")) != NULL
)
1788 Home
= my_tgetstr("ho","home");
1789 if (Home
== 0 || *Home
== '\0')
1791 if ((cursorm
= my_tgetstr("cm","cup")) != NULL
) {
1792 const char *t
= (const char *)my_tgoto(cursorm
, 0, 0);
1793 strncpy(cursorhome
, t
, sizeof(cursorhome
));
1794 cursorhome
[sizeof(cursorhome
)-1] = 0;
1798 EodClr
= my_tgetstr("cd","ed");
1799 if ((chBS
= my_tgetstr("le","cub1")) == NULL
)
1803 if ((shell
= getenv("SHELL")) == NULL
)
1806 no_intty
= tcgetattr(fileno(stdin
), &otty
);
1807 tcgetattr(fileno(stderr
), &otty
);
1809 slow_tty
= (otty
.c_cflag
& CBAUD
) < B1200
;
1810 hardtabs
= (otty
.c_oflag
& TABDLY
) != XTABS
;
1812 otty
.c_lflag
&= ~(ICANON
|ECHO
);
1813 otty
.c_cc
[VMIN
] = 1;
1814 otty
.c_cc
[VTIME
] = 0;
1822 if (read (2, &c
, 1) <= 0) {
1826 c
= otty
.c_cc
[VKILL
];
1831 static char *BS
= "\b";
1832 static char *BSB
= "\b \b";
1833 static char *CARAT
= "^";
1834 #define ERASEONECHAR \
1840 void ttyin (char buf
[], register int nmax
, char pchar
) {
1849 while (sp
- buf
< nmax
) {
1850 if (promptlen
> maxlen
) maxlen
= promptlen
;
1855 else if (((cc_t
) c
== otty
.c_cc
[VERASE
]) && !slash
) {
1860 if ((*sp
< ' ' && *sp
!= '\n') || *sp
== RUBOUT
) {
1867 if (!eraseln
) promptlen
= maxlen
;
1868 siglongjmp (restore
, 1);
1871 else if (((cc_t
) c
== otty
.c_cc
[VKILL
]) && !slash
) {
1883 while (promptlen
-- > 1)
1891 if (slash
&& ((cc_t
) c
== otty
.c_cc
[VKILL
]
1892 || (cc_t
) c
== otty
.c_cc
[VERASE
])) {
1899 if ((c
< ' ' && c
!= '\n' && c
!= ESC
) || c
== RUBOUT
) {
1900 c
+= (c
== RUBOUT
) ? -0100 : 0100;
1905 if (c
!= '\n' && c
!= ESC
) {
1913 if (!eraseln
) promptlen
= maxlen
;
1914 if (sp
- buf
>= nmax
- 1)
1915 error (_("Line too long"));
1918 /* return: 0 - unchanged, 1 - changed, -1 - overflow (unchanged) */
1919 int expand (char **outbuf
, char *inbuf
) {
1925 int tempsz
, xtra
, offset
;
1927 xtra
= strlen (fnames
[fnum
]) + strlen (shell_line
) + 1;
1928 tempsz
= 200 + xtra
;
1929 temp
= malloc(tempsz
);
1931 error (_("Out of memory"));
1936 while ((c
= *inpstr
++) != '\0'){
1937 offset
= outstr
-temp
;
1938 if (tempsz
-offset
-1 < xtra
) {
1939 tempsz
+= 200 + xtra
;
1940 temp
= realloc(temp
, tempsz
);
1942 error (_("Out of memory"));
1945 outstr
= temp
+ offset
;
1950 strcpy (outstr
, fnames
[fnum
]);
1951 outstr
+= strlen (fnames
[fnum
]);
1958 error (_("No previous command to substitute for"));
1959 strcpy (outstr
, shell_line
);
1960 outstr
+= strlen (shell_line
);
1964 if (*inpstr
== '%' || *inpstr
== '!') {
1965 *outstr
++ = *inpstr
++;
1977 void show (char c
) {
1980 if ((c
< ' ' && c
!= '\n' && c
!= ESC
) || c
== RUBOUT
) {
1981 c
+= (c
== RUBOUT
) ? -0100 : 0100;
1990 void errwrite (char *txt
)
1992 write (fileno(stderr
), txt
, strlen(txt
));
1995 void errwrite1 (char *sym
)
1997 write (fileno(stderr
), sym
, 1);
2000 void error (char *mess
)
2006 promptlen
+= strlen (mess
);
2007 if (Senter
&& Sexit
) {
2008 my_putstring (Senter
);
2010 my_putstring (Sexit
);
2016 siglongjmp (restore
, 1);
2021 otty
.c_lflag
&= ~(ICANON
|ECHO
);
2022 otty
.c_cc
[VMIN
] = 1; /* read at least 1 char */
2023 otty
.c_cc
[VTIME
] = 0; /* no timeout */
2024 stty(fileno(stderr
), &otty
);
2029 return putc(c
, stdout
);
2037 tputs(ULexit
, 1, ourputch
);
2041 otty
.c_lflag
|= ICANON
|ECHO
;
2042 otty
.c_cc
[VMIN
] = savetty0
.c_cc
[VMIN
];
2043 otty
.c_cc
[VTIME
] = savetty0
.c_cc
[VTIME
];
2044 stty(fileno(stderr
), &savetty0
);
2047 void rdline (register FILE *f
)
2053 while ((c
= Getc (f
)) != '\n' && c
!= EOF
&& p
- Line
< LINSIZ
- 1)
2060 /* Come here when we get a suspend signal from the terminal */
2062 void onsusp (int dummy
) {
2063 sigset_t signals
, oldmask
;
2065 /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
2066 signal(SIGTTOU
, SIG_IGN
);
2069 signal(SIGTTOU
, SIG_DFL
);
2070 /* Send the TSTP signal to suspend our process group */
2071 signal(SIGTSTP
, SIG_DFL
);
2073 /* unblock SIGTSTP or we won't be able to suspend ourself */
2074 sigemptyset(&signals
);
2075 sigaddset(&signals
, SIGTSTP
);
2076 sigprocmask(SIG_UNBLOCK
, &signals
, &oldmask
);
2079 /* Pause for station break */
2081 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
2084 signal (SIGTSTP
, onsusp
);
2087 siglongjmp (restore
, 1);