]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - text-utils/pg.c
2 * pg - A clone of the System V CRT paging utility.
4 * Copyright (c) 2000-2001 Gunnar Ritter. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 /* Sccsid @(#)pg.c 1.44 (gritter) 2/8/02 - modified for util-linux */
35 * #define _XOPEN_SOURCE 500L
37 * Adding this define gives us the correct prototypes for fseeko, ftello,
38 * but (for some glibc versions) conflicting prototype for wcwidth.
39 * So, avoid defining _XOPEN_SOURCE, and give prototypes for fseeko, ftello
43 #include <sys/types.h>
47 #include <sys/ioctl.h>
49 #include <sys/termios.h>
73 #include "../defines.h" /* for HAVE_fseeko */
75 #define READBUF LINE_MAX /* size of input buffer */
76 #define CMDBUF 255 /* size of command buffer */
77 #define TABSIZE 8 /* spaces consumed by tab character */
80 * Avoid the message "`var' might be clobbered by `longjmp' or `vfork'"
82 #define CLOBBGRD(a) (void)(&(a));
84 #define cuc(c) ((c) & 0377)
86 enum { FORWARD
= 1, BACKWARD
= 2 }; /* search direction */
87 enum { TOP
, MIDDLE
, BOTTOM
}; /* position of matching line */
90 * States for syntax-aware command line editor.
107 char cmdline
[CMDBUF
];
111 char pattern
[CMDBUF
];
116 * Position of file arguments on argv[] to main()
124 void (*oldint
)(int); /* old SIGINT handler */
125 void (*oldquit
)(int); /* old SIGQUIT handler */
126 void (*oldterm
)(int); /* old SIGTERM handler */
127 char *tty
; /* result of ttyname(1) */
128 char *progname
; /* program name */
129 unsigned ontty
; /* whether running on tty device */
130 unsigned exitstatus
; /* exit status */
131 int pagelen
= 23; /* lines on a single screen page */
132 int ttycols
= 79; /* screen columns (starting at 0) */
133 struct termios otio
; /* old termios settings */
134 int tinfostat
= -1; /* terminfo routines initialized */
135 int searchdisplay
= TOP
; /* matching line position */
136 regex_t re
; /* regular expression to search for */
137 int remembered
; /* have a remembered search string */
138 int cflag
; /* clear screen before each page */
139 int eflag
; /* suppress (EOF) */
140 int fflag
; /* do not split lines */
141 int nflag
; /* no newline for commands required */
142 int rflag
; /* "restricted" pg */
143 int sflag
; /* use standout mode */
144 char *pstring
= ":"; /* prompt string */
145 char *searchfor
; /* search pattern from argv[] */
146 int havepagelen
; /* page length is manually defined */
147 long startline
; /* start line from argv[] */
148 int nextfile
= 1; /* files to advance */
149 jmp_buf jmpenv
; /* jump from signal handlers */
150 int canjump
; /* jmpenv is valid */
151 wchar_t wbuf
[READBUF
]; /* used in several widechar routines */
153 const char *copyright
=
154 "@(#)pg 1.44 2/8/02. Copyright (c) 2000-2001 Gunnar Ritter. ";
155 const char *helpscreen
= "All rights reserved.\n\
156 -------------------------------------------------------\n\
158 q or Q quit program\n\
159 <newline> next page\n\
160 f skip a page forward\n\
161 d or ^D next halfpage\n\
164 /regex/ search forward for regex\n\
165 ?regex? or ^regex^ search backward for regex\n\
166 . or ^L redraw screen\n\
167 w or z set page size and go to next page\n\
168 s filename save current file to filename\n\
169 !command shell escape\n\
170 p go to previous file\n\
173 Many commands accept preceding numbers, for example:\n\
174 +1<newline> (next page); -1<newline> (previous page); 1<newline> (first page).\n\
176 See pg(1) for more information.\n\
177 -------------------------------------------------------\n";
180 #if defined (_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS) == 64
181 extern int fseeko64(FILE *f
, off_t off
, int whence
);
182 extern off_t
ftello64(FILE *f
);
183 #define my_fseeko fseeko64
184 #define my_ftello ftello64
186 extern int fseeko(FILE *f
, off_t off
, int whence
);
187 extern off_t
ftello(FILE *f
);
188 #define my_fseeko fseeko
189 #define my_ftello ftello
192 static int my_fseeko(FILE *f
, off_t off
, int whence
) {
193 return fseek(f
, (long) off
, whence
);
195 static off_t
my_ftello(FILE *f
) {
196 return (off_t
) ftell(f
);
200 #ifdef USE_SIGSET /* never defined */
201 /* sigset and sigrelse are obsolete - use when POSIX stuff is unavailable */
202 #define my_sigset sigset
203 #define my_sigrelse sigrelse
205 static int my_sigrelse(int sig
) {
208 if (sigemptyset(&sigs
) || sigaddset(&sigs
, sig
))
210 return sigprocmask(SIG_UNBLOCK
, &sigs
, NULL
);
212 typedef void (*my_sighandler_t
)(int);
213 static my_sighandler_t
my_sigset(int sig
, my_sighandler_t disp
) {
214 struct sigaction act
, oact
;
216 act
.sa_handler
= disp
;
217 if (sigemptyset(&act
.sa_mask
))
220 if (sigaction(sig
, &act
, &oact
))
222 if (my_sigrelse(sig
))
224 return oact
.sa_handler
;
234 exit(status
< 0100 ? status
: 077);
238 * Memory allocator including check.
243 char *m
= (char *)malloc(s
);
245 write(2, "Out of memory\n", 14);
252 * Usage message and similar routines.
257 fprintf(stderr
, _("%s: Usage: %s [-number] [-p string] [-cefnrs] "
258 "[+line] [+/pattern/] [files]\n"),
266 fprintf(stderr
, _("%s: option requires an argument -- %s\n"),
274 fprintf(stderr
, _("%s: illegal option -- %s\n"), progname
, s
);
278 #ifdef ENABLE_WIDECHAR
280 * A mbstowcs()-alike function that transparently handles invalid sequences.
283 xmbstowcs(wchar_t *pwcs
, const char *s
, size_t nwcs
)
288 mbtowc(pwcs
, NULL
, MB_CUR_MAX
);
290 if ((c
= mbtowc(pwcs
, s
, MB_CUR_MAX
)) < 0) {
300 mbtowc(pwcs
, NULL
, MB_CUR_MAX
);
306 * Helper function for tputs().
312 return write(1, &c
, 1);
316 * Write messages to terminal.
323 if (*message
!= '\n' && sflag
)
324 vidputs(A_STANDOUT
, outcap
);
325 write(1, message
, strlen(message
));
326 if (*message
!= '\n' && sflag
)
327 vidputs(A_NORMAL
, outcap
);
331 * Get the window size.
336 static int initialized
, envlines
, envcols
, deflines
, defcols
;
338 struct winsize winsz
;
343 if (initialized
== 0) {
344 if ((p
= getenv("LINES")) != NULL
&& *p
!= '\0')
345 if ((envlines
= atoi(p
)) < 0)
347 if ((p
= getenv("COLUMNS")) != NULL
&& *p
!= '\0')
348 if ((envcols
= atoi(p
)) < 0)
350 /* terminfo values. */
351 if (tinfostat
!= 1 || columns
== 0)
355 if (tinfostat
!= 1 || lines
== 0)
362 badioctl
= ioctl(1, TIOCGWINSZ
, &winsz
);
365 ttycols
= envcols
- 1;
368 ttycols
= winsz
.ws_col
- 1;
371 ttycols
= defcols
- 1;
372 if (havepagelen
== 0) {
374 pagelen
= envlines
- 1;
377 pagelen
= winsz
.ws_row
- 1;
380 pagelen
= deflines
- 1;
385 * Message if skipping parts of files.
391 mesg(_("...skipping forward\n"));
393 mesg(_("...skipping backward\n"));
397 * Signal handler while reading from input file.
400 sighandler(int signum
)
402 if (canjump
&& (signum
== SIGINT
|| signum
== SIGQUIT
))
403 longjmp(jmpenv
, signum
);
404 tcsetattr(1, TCSADRAIN
, &otio
);
409 * Check whether the requested file was specified on the command line.
414 if (files
.current
+ nextfile
>= files
.last
) {
415 mesg(_("No next file"));
418 if (files
.current
+ nextfile
< files
.first
) {
419 mesg(_("No previous file"));
425 #ifdef ENABLE_WIDECHAR
427 * Return the last character that will fit on the line at col columns
428 * in case MB_CUR_MAX > 1.
431 endline_for_mb(unsigned col
, char *s
)
439 if ((wl
= xmbstowcs(wbuf
, t
, sizeof wbuf
- 1)) == (size_t)-1)
442 while (*p
!= L
'\0') {
452 * No cursor movement.
469 pos
+= TABSIZE
- (pos
% TABSIZE
);
477 else if (pos
> col
+ 1)
479 * wcwidth() found a character that
480 * has multiple columns. What happens
481 * now? Assume the terminal will print
482 * the entire character onto the next
497 if ((pos
= wcstombs(NULL
, p
, READBUF
)) == -1)
504 * Return the last character that will fit on the line at col columns.
507 endline(unsigned col
, char *s
)
512 #ifdef ENABLE_WIDECHAR
514 return endline_for_mb(col
, s
);
527 * No cursor movement.
544 pos
+= TABSIZE
- (pos
% TABSIZE
);
565 * Clear the current line on the terminal's screen.
570 char *buf
= (char *)smalloc(ttycols
+ 2);
571 memset(buf
, ' ', ttycols
+ 2);
573 buf
[ttycols
+ 1] = '\r';
574 write(1, buf
, ttycols
+ 2);
579 * Evaluate a command character's semantics.
585 case '1': case '2': case '3': case '4': case '5':
586 case '6': case '7': case '8': case '9': case '0':
591 case 'l': case 'd': case '\004': case 'f': case 'z':
592 case '.': case '\014': case '$': case 'n': case 'p':
593 case 'w': case 'h': case 'q': case 'Q':
595 case '/': case '?': case '^':
599 case 'm': case 'b': case 't':
604 tputs(bell
, 1, outcap
);
605 #endif /* PGNOBELL */
611 * Get the count and ignore last character of string.
614 getcount(char *cmdstr
)
622 buf
= (char *)smalloc(strlen(cmdstr
) + 1);
624 if (cmd
.key
!= '\0') {
625 if (cmd
.key
== '/' || cmd
.key
== '?' || cmd
.key
== '^') {
626 if ((p
= strchr(buf
, cmd
.key
)) != NULL
)
629 *(buf
+ strlen(buf
) - 1) = '\0';
633 if (buf
[0] == '-' && buf
[1] == '\0') {
646 * Read what the user writes at the prompt. This is tricky because
647 * we check for valid input.
650 prompt(long long pageno
)
656 char b
[LINE_MAX
], *p
;
659 if ((p
= strstr(pstring
, "%d")) == NULL
) {
663 sprintf(b
+ (p
- pstring
), "%lld", pageno
);
668 cmd
.key
= cmd
.addon
= cmd
.cmdline
[0] = '\0';
671 tio
.c_lflag
&= ~(ICANON
| ECHO
);
674 tcsetattr(1, TCSADRAIN
, &tio
);
675 tcflush(1, TCIFLUSH
);
677 switch (read(1, &key
, 1)) {
682 if (key
== tio
.c_cc
[VERASE
]) {
684 write(1, "\b \b", 3);
685 cmd
.cmdline
[--cmd
.cmdlen
] = '\0';
699 if (cmd
.cmdline
[cmd
.cmdlen
- 1]
702 while(cmd
.cmdline
[cmd
.cmdlen
709 if (strchr(cmd
.cmdline
, cmd
.key
)
718 if (cmd
.cmdlen
== 0) {
724 if (key
== tio
.c_cc
[VKILL
]) {
727 cmd
.cmdline
[0] = '\0';
732 if (key
== '\n' || (nflag
&& state
== COUNT
&& key
== ' '))
734 if (cmd
.cmdlen
>= CMDBUF
- 1)
749 if (getstate(key
) != ADDON_FIN
)
758 searchdisplay
= MIDDLE
;
761 searchdisplay
= BOTTOM
;
769 state
= getstate(key
);
772 if (cmd
.cmdlen
!= 0) {
788 cmd
.cmdline
[cmd
.cmdlen
++] = key
;
789 cmd
.cmdline
[cmd
.cmdlen
] = '\0';
790 if (nflag
&& state
== CMD_FIN
)
794 tcsetattr(1, TCSADRAIN
, &otio
);
796 cmd
.count
= getcount(cmd
.cmdline
);
799 #ifdef ENABLE_WIDECHAR
801 * Remove backspace formatting, for searches
802 * in case MB_CUR_MAX > 1.
809 size_t l
= strlen(s
), wl
;
812 if ((wl
= xmbstowcs(wbuf
, p
, sizeof wbuf
)) == (size_t)-1)
814 for (wp
= wbuf
, wq
= wbuf
, i
= 0; *wp
!= L
'\0' && i
< wl
;
826 wcstombs(s
, wp
, l
+ 1);
833 * Remove backspace formatting, for searches.
840 #ifdef ENABLE_WIDECHAR
842 return colb_for_mb(s
);
845 for (q
= s
; *p
!= '\0'; p
++, q
++) {
859 #ifdef ENABLE_WIDECHAR
861 * Convert nonprintable characters to spaces
862 * in case MB_CUR_MAX > 1.
865 makeprint_for_mb(char *s
, size_t l
)
871 if ((wl
= xmbstowcs(wbuf
, t
, sizeof wbuf
)) == (size_t)-1)
874 if (!iswprint(*wp
) && *wp
!= L
'\n' && *wp
!= L
'\r'
875 && *wp
!= L
'\b' && *wp
!= L
'\t')
885 * Convert nonprintable characters to spaces.
888 makeprint(char *s
, size_t l
)
890 #ifdef ENABLE_WIDECHAR
892 return makeprint_for_mb(s
, l
);
896 if (!isprint(cuc(*s
)) && *s
!= '\n' && *s
!= '\r'
897 && *s
!= '\b' && *s
!= '\t')
904 * Strip backslash characters from the given string.
916 } while (*s
++ != '\0');
920 * Extract the search pattern off the command line.
927 if (cmd
.addon
== '\0')
928 p
= cmd
.cmdline
+ strlen(cmd
.cmdline
) - 1;
930 p
= cmd
.cmdline
+ strlen(cmd
.cmdline
) - 2;
935 if ((p
= strchr(cmd
.cmdline
, cmd
.key
)) != NULL
) {
943 * Process errors that occurred in temporary file operations.
946 tmperr(FILE *f
, char *ftype
)
949 fprintf(stderr
, _("%s: Read error from %s file\n"),
953 * Most likely '\0' in input.
955 fprintf(stderr
, _("%s: Unexpected EOF in %s file\n"),
958 fprintf(stderr
, _("%s: Unknown error in %s file\n"),
964 * perror()-like, but showing the program's name.
967 pgerror(int eno
, char *string
)
969 fprintf(stderr
, "%s: %s: %s\n", progname
, string
, strerror(eno
));
973 * Read the file and respond to user input.
974 * Beware: long and ugly.
977 pgfile(FILE *f
, char *name
)
979 off_t pos
, oldpos
, fpos
;
980 off_t line
= 0, fline
= 0, bline
= 0, oldline
= 0, eofline
= 0;
983 * These are the line counters:
984 * line the line desired to display
985 * fline the current line of the input file
986 * bline the current line of the file buffer
987 * oldline the line before a search was started
988 * eofline the last line of the file if it is already reached
989 * dline the line on the display
992 unsigned searchcount
= 0;
994 * Advance to EOF immediately.
998 * EOF has been reached by `line'.
1002 * f and fbuf refer to the same file.
1008 char b
[READBUF
+ 1];
1011 * fbuf an exact copy of the input file as it gets read
1012 * find index table for input, one entry per line
1013 * save for the s command, to save to a file
1015 FILE *fbuf
, *find
, *save
;
1017 /* silence compiler - it may warn about longjmp() */
1026 CLOBBGRD(searchcount
);
1035 * Just copy stdin to stdout.
1037 while ((sz
= fread(b
, sizeof *b
, READBUF
, f
)) != 0)
1040 pgerror(errno
, name
);
1045 if ((fpos
= my_fseeko(f
, (off_t
)0, SEEK_SET
)) == -1)
1052 if (fbuf
== NULL
|| find
== NULL
) {
1053 fprintf(stderr
, _("%s: Cannot create tempfile\n"), progname
);
1060 rerror
= regcomp(&re
, searchfor
, REG_NOSUB
| REG_NEWLINE
);
1062 mesg(_("RE error: "));
1063 regerror(rerror
, &re
, b
, READBUF
);
1070 for (line
= startline
; ; ) {
1072 * Get a line from input file or buffer.
1075 my_fseeko(find
, line
* sizeof pos
, SEEK_SET
);
1076 if (fread(&pos
, sizeof pos
, 1, find
) == 0)
1077 tmperr(find
, "index");
1078 my_fseeko(find
, (off_t
)0, SEEK_END
);
1079 my_fseeko(fbuf
, pos
, SEEK_SET
);
1080 if (fgets(b
, READBUF
, fbuf
) == NULL
)
1081 tmperr(fbuf
, "buffer");
1082 } else if (eofline
== 0) {
1083 my_fseeko(find
, (off_t
)0, SEEK_END
);
1086 my_fseeko(fbuf
, (off_t
)0, SEEK_END
);
1087 pos
= my_ftello(fbuf
);
1088 if ((sig
= setjmp(jmpenv
)) != 0) {
1094 my_fseeko(fbuf
, pos
, SEEK_SET
);
1100 my_fseeko(f
, fpos
, SEEK_SET
);
1102 p
= fgets(b
, READBUF
, f
);
1104 if ((fpos
= my_ftello(f
)) == -1)
1105 pgerror(errno
, name
);
1108 if (p
== NULL
|| *b
== '\0') {
1110 pgerror(errno
, name
);
1117 fwrite(&pos
, sizeof pos
, 1, find
);
1121 while (*(p
= endline(ttycols
,
1124 pos
= oldpos
+ (p
- b
);
1134 } while (line
> bline
++);
1141 if (search
== FORWARD
) {
1144 search
= searchcount
= 0;
1145 mesg(_("Pattern not found"));
1151 if (regexec(&re
, b
, 0, NULL
, 0) == 0) {
1154 if (searchcount
== 0) {
1156 switch (searchdisplay
) {
1161 line
-= pagelen
/ 2 + 1;
1170 } else if (eof
) { /*
1171 * We are not searching.
1174 } else if (*b
!= '\0') {
1175 if (cflag
&& clear_screen
) {
1178 tputs(clear_screen
, 1, outcap
);
1183 if (eofline
&& line
== eofline
)
1186 if ((sig
= setjmp(jmpenv
)) != 0) {
1194 p
= endline(ttycols
, b
);
1202 if (dline
>= pagelen
|| eof
) {
1204 * Time for prompting!
1206 if (eof
&& seekeof
) {
1208 if (line
>= pagelen
)
1217 if (fline
== 0 || eflag
)
1221 prompt((line
- 1) / pagelen
+ 1);
1229 searchcount
= cmd
.count
;
1231 if (p
!= NULL
&& *p
) {
1232 if (remembered
== 1)
1234 rerror
= regcomp(&re
, p
,
1235 REG_NOSUB
| REG_NEWLINE
);
1237 mesg(_("RE error: "));
1238 sz
= regerror(rerror
, &re
,
1244 } else if (remembered
== 0) {
1245 mesg(_("No remembered search string"));
1256 searchcount
= cmd
.count
;
1258 if (p
!= NULL
&& *p
) {
1259 if (remembered
== 1)
1261 rerror
= regcomp(&re
, p
,
1262 REG_NOSUB
| REG_NEWLINE
);
1265 regerror(rerror
, &re
,
1271 } else if (remembered
== 0) {
1272 mesg("No remembered search string");
1279 my_fseeko(find
, --line
* sizeof pos
,
1281 if(fread(&pos
, sizeof pos
, 1,find
)==0)
1282 tmperr(find
, "index");
1283 my_fseeko(find
, (off_t
)0, SEEK_END
);
1284 my_fseeko(fbuf
, pos
, SEEK_SET
);
1285 if (fgets(b
, READBUF
, fbuf
) == NULL
)
1286 tmperr(fbuf
, "buffer");
1288 if (regexec(&re
, b
, 0, NULL
, 0) == 0)
1290 if (searchcount
== 0)
1295 search
= searchcount
= 0;
1296 mesg(_("Pattern not found"));
1299 eof
= search
= dline
= 0;
1301 switch (searchdisplay
) {
1306 line
-= pagelen
/ 2;
1322 while (*++p
== ' ');
1325 save
= fopen(p
, "wb");
1328 mesg(_("Cannot open "));
1331 mesg(strerror(cmd
.count
));
1337 my_fseeko(find
, (off_t
)0, SEEK_END
);
1340 my_fseeko(fbuf
,(off_t
)0,SEEK_END
);
1341 pos
= my_ftello(fbuf
);
1342 if (fgets(b
, READBUF
, f
) == NULL
) {
1348 fwrite(&pos
, sizeof pos
, 1, find
);
1352 while (*(p
= endline(ttycols
,
1355 pos
= oldpos
+ (p
- b
);
1366 my_fseeko(fbuf
, (off_t
)0, SEEK_SET
);
1367 while ((sz
= fread(b
, sizeof *b
, READBUF
,
1370 * No error check for compat.
1372 fwrite(b
, sizeof *b
, sz
, save
);
1375 my_fseeko(fbuf
, (off_t
)0, SEEK_END
);
1382 if (*cmd
.cmdline
!= 'l')
1385 cmd
.count
= 1; /* compat */
1386 if (isdigit(cuc(*cmd
.cmdline
))) {
1387 line
= cmd
.count
- 2;
1390 if (cmd
.count
!= 1) {
1391 line
+= cmd
.count
- 1
1397 * Nothing to do if count==1.
1403 * Half screen forward.
1405 case '\004': /* ^D */
1406 if (*cmd
.cmdline
!= cmd
.key
)
1409 cmd
.count
= 1; /* compat */
1410 line
+= (cmd
.count
* pagelen
/ 2)
1420 cmd
.count
= 1; /* compat */
1421 line
+= cmd
.count
* pagelen
- 2;
1424 if (*cmd
.cmdline
!= 'f')
1428 if (eofline
&& line
>= eofline
)
1435 * Just a number, or '-', or <newline>.
1438 cmd
.count
= 1; /* compat */
1439 if (isdigit(cuc(*cmd
.cmdline
)))
1440 line
= (cmd
.count
- 1) * pagelen
- 2;
1442 line
+= (cmd
.count
- 1)
1443 * (pagelen
- 1) - 2;
1444 if (*cmd
.cmdline
!= '\0')
1446 if (cmd
.count
!= 1) {
1466 case '\014': /* ^L */
1471 if (line
>= pagelen
)
1483 mesg(_(": !command not allowed in "
1488 write(1, cmd
.cmdline
,
1489 strlen(cmd
.cmdline
));
1491 my_sigset(SIGINT
, SIG_IGN
);
1492 my_sigset(SIGQUIT
, SIG_IGN
);
1493 switch (cpid
= fork()) {
1495 p
= getenv("SHELL");
1496 if (p
== NULL
) p
= "/bin/sh";
1500 if (isatty(0) == 0) {
1502 open(tty
, O_RDONLY
);
1506 my_sigset(SIGINT
, oldint
);
1507 my_sigset(SIGQUIT
, oldquit
);
1508 my_sigset(SIGTERM
, oldterm
);
1510 cmd
.cmdline
+ 1, NULL
);
1515 mesg(_("fork() failed, "
1516 "try again later\n"));
1519 while (wait(NULL
) != cpid
);
1521 my_sigset(SIGINT
, sighandler
);
1522 my_sigset(SIGQUIT
, sighandler
);
1530 write(1, copyright
+ 4, strlen(copyright
+ 4));
1531 write(1, helpscreen
, strlen(helpscreen
));
1539 nextfile
= cmd
.count
;
1552 nextfile
= 0 - cmd
.count
;
1573 if (*cmd
.cmdline
!= cmd
.key
)
1574 pagelen
= ++cmd
.count
;
1582 if (cflag
&& dline
== 1) {
1596 main(int argc
, char **argv
)
1602 progname
= basename(argv
[0]);
1604 setlocale(LC_MESSAGES
, "");
1605 bindtextdomain(PACKAGE
, LOCALEDIR
);
1606 textdomain(PACKAGE
);
1608 if (tcgetattr(1, &otio
) == 0) {
1610 oldint
= my_sigset(SIGINT
, sighandler
);
1611 oldquit
= my_sigset(SIGQUIT
, sighandler
);
1612 oldterm
= my_sigset(SIGTERM
, sighandler
);
1613 setlocale(LC_CTYPE
, "");
1614 setlocale(LC_COLLATE
, "");
1616 setupterm(NULL
, 1, &tinfostat
);
1618 helpscreen
= _(helpscreen
);
1620 for (arg
= 1; argv
[arg
]; arg
++) {
1621 if (*argv
[arg
] == '+')
1623 if (*argv
[arg
] != '-' || argv
[arg
][1] == '\0')
1626 for (i
= 1; argv
[arg
][i
]; i
++) {
1627 switch (argv
[arg
][i
]) {
1629 if (i
!= 1 || argv
[arg
][i
+ 1])
1630 invopt(&argv
[arg
][i
]);
1632 case '1': case '2': case '3': case '4': case '5':
1633 case '6': case '7': case '8': case '9': case '0':
1634 pagelen
= atoi(argv
[arg
] + i
);
1650 if (argv
[arg
][i
+ 1]) {
1651 pstring
= &argv
[arg
][i
+ 1];
1652 } else if (argv
[++arg
]) {
1654 pstring
= argv
[arg
];
1665 invopt(&argv
[arg
][i
]);
1672 for (arg
= 1; argv
[arg
]; arg
++) {
1673 if (*argv
[arg
] == '-') {
1674 if (argv
[arg
][1] == '-') {
1678 if (argv
[arg
][1] == '\0')
1680 if (argv
[arg
][1] == 'p' && argv
[arg
][2] == '\0')
1684 if (*argv
[arg
] != '+')
1687 switch (*(argv
[arg
] + 1)) {
1691 case '1': case '2': case '3': case '4': case '5':
1692 case '6': case '7': case '8': case '9': case '0':
1693 startline
= atoi(argv
[arg
] + 1);
1696 searchfor
= argv
[arg
] + 2;
1697 if (*searchfor
== '\0')
1699 p
= searchfor
+ strlen(searchfor
) - 1;
1700 if (*p
== '/') *p
= '\0';
1701 if (*searchfor
== '\0')
1709 pgfile(stdin
, "stdin");
1712 files
.last
= arg
+ argc
- 1;
1713 for ( ; argv
[arg
]; arg
+= nextfile
) {
1715 files
.current
= arg
;
1717 static int firsttime
;
1719 if (firsttime
> 1) {
1720 mesg(_("(Next file: "));
1733 nextfile
= cmd
.count
;
1746 nextfile
= 0 - cmd
.count
;
1760 if (strcmp(argv
[arg
], "-") == 0)
1763 input
= fopen(argv
[arg
], "r");
1764 if (input
== NULL
) {
1765 pgerror(errno
, argv
[arg
]);
1770 if (ontty
== 0 && argc
> 2) {
1772 * Use the prefix as specified by SUSv2.
1774 write(1, "::::::::::::::\n", 15);
1775 write(1, argv
[arg
], strlen(argv
[arg
]));
1776 write(1, "\n::::::::::::::\n", 16);
1778 pgfile(input
, argv
[arg
]);