]>
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>
69 #include "../defines.h" /* for HAVE_fseeko */
71 #define READBUF LINE_MAX /* size of input buffer */
72 #define CMDBUF 255 /* size of command buffer */
73 #define TABSIZE 8 /* spaces consumed by tab character */
76 * Avoid the message "`var' might be clobbered by `longjmp' or `vfork'"
78 #define CLOBBGRD(a) (void)(&(a));
80 #define cuc(c) ((c) & 0377)
82 enum { FORWARD
= 1, BACKWARD
= 2 }; /* search direction */
83 enum { TOP
, MIDDLE
, BOTTOM
}; /* position of matching line */
86 * States for syntax-aware command line editor.
103 char cmdline
[CMDBUF
];
107 char pattern
[CMDBUF
];
112 * Position of file arguments on argv[] to main()
120 void (*oldint
)(int); /* old SIGINT handler */
121 void (*oldquit
)(int); /* old SIGQUIT handler */
122 void (*oldterm
)(int); /* old SIGTERM handler */
123 char *tty
; /* result of ttyname(1) */
124 char *progname
; /* program name */
125 unsigned ontty
; /* whether running on tty device */
126 unsigned exitstatus
; /* exit status */
127 int pagelen
= 23; /* lines on a single screen page */
128 int ttycols
= 79; /* screen columns (starting at 0) */
129 struct termios otio
; /* old termios settings */
130 int tinfostat
= -1; /* terminfo routines initialized */
131 int searchdisplay
= TOP
; /* matching line position */
132 regex_t re
; /* regular expression to search for */
133 int remembered
; /* have a remembered search string */
134 int cflag
; /* clear screen before each page */
135 int eflag
; /* suppress (EOF) */
136 int fflag
; /* do not split lines */
137 int nflag
; /* no newline for commands required */
138 int rflag
; /* "restricted" pg */
139 int sflag
; /* use standout mode */
140 char *pstring
= ":"; /* prompt string */
141 char *searchfor
; /* search pattern from argv[] */
142 int havepagelen
; /* page length is manually defined */
143 long startline
; /* start line from argv[] */
144 int nextfile
= 1; /* files to advance */
145 jmp_buf jmpenv
; /* jump from signal handlers */
146 int canjump
; /* jmpenv is valid */
147 wchar_t wbuf
[READBUF
]; /* used in several widechar routines */
149 const char *copyright
=
150 "@(#)pg 1.44 2/8/02. Copyright (c) 2000-2001 Gunnar Ritter. ";
151 const char *helpscreen
= "All rights reserved.\n\
152 -------------------------------------------------------\n\
154 q or Q quit program\n\
155 <newline> next page\n\
156 f skip a page forward\n\
157 d or ^D next halfpage\n\
160 /regex/ search forward for regex\n\
161 ?regex? or ^regex^ search backward for regex\n\
162 . or ^L redraw screen\n\
163 w or z set page size and go to next page\n\
164 s filename save current file to filename\n\
165 !command shell escape\n\
166 p go to previous file\n\
169 Many commands accept preceding numbers, for example:\n\
170 +1<newline> (next page); -1<newline> (previous page); 1<newline> (first page).\n\
172 See pg(1) for more information.\n\
173 -------------------------------------------------------\n";
176 #if defined (_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS) == 64
177 extern int fseeko64(FILE *f
, off_t off
, int whence
);
178 extern off_t
ftello64(FILE *f
);
179 #define my_fseeko fseeko64
180 #define my_ftello ftello64
182 extern int fseeko(FILE *f
, off_t off
, int whence
);
183 extern off_t
ftello(FILE *f
);
184 #define my_fseeko fseeko
185 #define my_ftello ftello
188 static int my_fseeko(FILE *f
, off_t off
, int whence
) {
189 return fseek(f
, (long) off
, whence
);
191 static off_t
my_ftello(FILE *f
) {
192 return (off_t
) ftell(f
);
196 #ifdef USE_SIGSET /* never defined */
197 /* sigset and sigrelse are obsolete - use when POSIX stuff is unavailable */
198 #define my_sigset sigset
199 #define my_sigrelse sigrelse
201 static int my_sigrelse(int sig
) {
204 if (sigemptyset(&sigs
) || sigaddset(&sigs
, sig
))
206 return sigprocmask(SIG_UNBLOCK
, &sigs
, NULL
);
208 typedef void (*my_sighandler_t
)(int);
209 static my_sighandler_t
my_sigset(int sig
, my_sighandler_t disp
) {
210 struct sigaction act
, oact
;
212 act
.sa_handler
= disp
;
213 if (sigemptyset(&act
.sa_mask
))
216 if (sigaction(sig
, &act
, &oact
))
218 if (my_sigrelse(sig
))
220 return oact
.sa_handler
;
230 exit(status
< 0100 ? status
: 077);
234 * Memory allocator including check.
239 char *m
= (char *)malloc(s
);
241 write(2, "Out of memory\n", 14);
248 * Usage message and similar routines.
253 fprintf(stderr
, _("%s: Usage: %s [-number] [-p string] [-cefnrs] "
254 "[+line] [+/pattern/] [files]\n"),
262 fprintf(stderr
, _("%s: option requires an argument -- %s\n"),
270 fprintf(stderr
, _("%s: illegal option -- %s\n"), progname
, s
);
274 #ifdef ENABLE_WIDECHAR
276 * A mbstowcs()-alike function that transparently handles invalid sequences.
279 xmbstowcs(wchar_t *pwcs
, const char *s
, size_t nwcs
)
284 mbtowc(pwcs
, NULL
, MB_CUR_MAX
);
286 if ((c
= mbtowc(pwcs
, s
, MB_CUR_MAX
)) < 0) {
296 mbtowc(pwcs
, NULL
, MB_CUR_MAX
);
302 * Helper function for tputs().
308 return write(1, &c
, 1);
312 * Write messages to terminal.
319 if (*message
!= '\n' && sflag
)
320 vidputs(A_STANDOUT
, outcap
);
321 write(1, message
, strlen(message
));
322 if (*message
!= '\n' && sflag
)
323 vidputs(A_NORMAL
, outcap
);
327 * Get the window size.
332 static int initialized
, envlines
, envcols
, deflines
, defcols
;
334 struct winsize winsz
;
339 if (initialized
== 0) {
340 if ((p
= getenv("LINES")) != NULL
&& *p
!= '\0')
341 if ((envlines
= atoi(p
)) < 0)
343 if ((p
= getenv("COLUMNS")) != NULL
&& *p
!= '\0')
344 if ((envcols
= atoi(p
)) < 0)
346 /* terminfo values. */
347 if (tinfostat
!= 1 || columns
== 0)
351 if (tinfostat
!= 1 || lines
== 0)
358 badioctl
= ioctl(1, TIOCGWINSZ
, &winsz
);
361 ttycols
= envcols
- 1;
364 ttycols
= winsz
.ws_col
- 1;
367 ttycols
= defcols
- 1;
368 if (havepagelen
== 0) {
370 pagelen
= envlines
- 1;
373 pagelen
= winsz
.ws_row
- 1;
376 pagelen
= deflines
- 1;
381 * Message if skipping parts of files.
387 mesg(_("...skipping forward\n"));
389 mesg(_("...skipping backward\n"));
393 * Signal handler while reading from input file.
396 sighandler(int signum
)
398 if (canjump
&& (signum
== SIGINT
|| signum
== SIGQUIT
))
399 longjmp(jmpenv
, signum
);
400 tcsetattr(1, TCSADRAIN
, &otio
);
405 * Check whether the requested file was specified on the command line.
410 if (files
.current
+ nextfile
>= files
.last
) {
411 mesg(_("No next file"));
414 if (files
.current
+ nextfile
< files
.first
) {
415 mesg(_("No previous file"));
421 #ifdef ENABLE_WIDECHAR
423 * Return the last character that will fit on the line at col columns
424 * in case MB_CUR_MAX > 1.
427 endline_for_mb(unsigned col
, char *s
)
435 if ((wl
= xmbstowcs(wbuf
, t
, sizeof wbuf
- 1)) == (size_t)-1)
438 while (*p
!= L
'\0') {
448 * No cursor movement.
465 pos
+= TABSIZE
- (pos
% TABSIZE
);
473 else if (pos
> col
+ 1)
475 * wcwidth() found a character that
476 * has multiple columns. What happens
477 * now? Assume the terminal will print
478 * the entire character onto the next
493 if ((pos
= wcstombs(NULL
, p
, READBUF
)) == -1)
500 * Return the last character that will fit on the line at col columns.
503 endline(unsigned col
, char *s
)
508 #ifdef ENABLE_WIDECHAR
510 return endline_for_mb(col
, s
);
523 * No cursor movement.
540 pos
+= TABSIZE
- (pos
% TABSIZE
);
561 * Clear the current line on the terminal's screen.
566 char *buf
= (char *)smalloc(ttycols
+ 2);
567 memset(buf
, ' ', ttycols
+ 2);
569 buf
[ttycols
+ 1] = '\r';
570 write(1, buf
, ttycols
+ 2);
575 * Evaluate a command character's semantics.
581 case '1': case '2': case '3': case '4': case '5':
582 case '6': case '7': case '8': case '9': case '0':
587 case 'l': case 'd': case '\004': case 'f': case 'z':
588 case '.': case '\014': case '$': case 'n': case 'p':
589 case 'w': case 'h': case 'q': case 'Q':
591 case '/': case '?': case '^':
595 case 'm': case 'b': case 't':
600 tputs(bell
, 1, outcap
);
601 #endif /* PGNOBELL */
607 * Get the count and ignore last character of string.
610 getcount(char *cmdstr
)
618 buf
= (char *)smalloc(strlen(cmdstr
) + 1);
620 if (cmd
.key
!= '\0') {
621 if (cmd
.key
== '/' || cmd
.key
== '?' || cmd
.key
== '^') {
622 if ((p
= strchr(buf
, cmd
.key
)) != NULL
)
625 *(buf
+ strlen(buf
) - 1) = '\0';
629 if (buf
[0] == '-' && buf
[1] == '\0') {
642 * Read what the user writes at the prompt. This is tricky because
643 * we check for valid input.
646 prompt(long long pageno
)
652 char b
[LINE_MAX
], *p
;
655 if ((p
= strstr(pstring
, "%d")) == NULL
) {
659 sprintf(b
+ (p
- pstring
), "%lld", pageno
);
664 cmd
.key
= cmd
.addon
= cmd
.cmdline
[0] = '\0';
667 tio
.c_lflag
&= ~(ICANON
| ECHO
);
670 tcsetattr(1, TCSADRAIN
, &tio
);
671 tcflush(1, TCIFLUSH
);
673 switch (read(1, &key
, 1)) {
678 if (key
== tio
.c_cc
[VERASE
]) {
680 write(1, "\b \b", 3);
681 cmd
.cmdline
[--cmd
.cmdlen
] = '\0';
695 if (cmd
.cmdline
[cmd
.cmdlen
- 1]
698 while(cmd
.cmdline
[cmd
.cmdlen
705 if (strchr(cmd
.cmdline
, cmd
.key
)
714 if (cmd
.cmdlen
== 0) {
720 if (key
== tio
.c_cc
[VKILL
]) {
723 cmd
.cmdline
[0] = '\0';
728 if (key
== '\n' || (nflag
&& state
== COUNT
&& key
== ' '))
730 if (cmd
.cmdlen
>= CMDBUF
- 1)
745 if (getstate(key
) != ADDON_FIN
)
754 searchdisplay
= MIDDLE
;
757 searchdisplay
= BOTTOM
;
765 state
= getstate(key
);
768 if (cmd
.cmdlen
!= 0) {
784 cmd
.cmdline
[cmd
.cmdlen
++] = key
;
785 cmd
.cmdline
[cmd
.cmdlen
] = '\0';
786 if (nflag
&& state
== CMD_FIN
)
790 tcsetattr(1, TCSADRAIN
, &otio
);
792 cmd
.count
= getcount(cmd
.cmdline
);
795 #ifdef ENABLE_WIDECHAR
797 * Remove backspace formatting, for searches
798 * in case MB_CUR_MAX > 1.
805 size_t l
= strlen(s
), wl
;
808 if ((wl
= xmbstowcs(wbuf
, p
, sizeof wbuf
)) == (size_t)-1)
810 for (wp
= wbuf
, wq
= wbuf
, i
= 0; *wp
!= L
'\0' && i
< wl
;
822 wcstombs(s
, wp
, l
+ 1);
829 * Remove backspace formatting, for searches.
836 #ifdef ENABLE_WIDECHAR
838 return colb_for_mb(s
);
841 for (q
= s
; *p
!= '\0'; p
++, q
++) {
855 #ifdef ENABLE_WIDECHAR
857 * Convert nonprintable characters to spaces
858 * in case MB_CUR_MAX > 1.
861 makeprint_for_mb(char *s
, size_t l
)
867 if ((wl
= xmbstowcs(wbuf
, t
, sizeof wbuf
)) == (size_t)-1)
870 if (!iswprint(*wp
) && *wp
!= L
'\n' && *wp
!= L
'\r'
871 && *wp
!= L
'\b' && *wp
!= L
'\t')
881 * Convert nonprintable characters to spaces.
884 makeprint(char *s
, size_t l
)
886 #ifdef ENABLE_WIDECHAR
888 return makeprint_for_mb(s
, l
);
892 if (!isprint(cuc(*s
)) && *s
!= '\n' && *s
!= '\r'
893 && *s
!= '\b' && *s
!= '\t')
900 * Strip backslash characters from the given string.
912 } while (*s
++ != '\0');
916 * Extract the search pattern off the command line.
923 if (cmd
.addon
== '\0')
924 p
= cmd
.cmdline
+ strlen(cmd
.cmdline
) - 1;
926 p
= cmd
.cmdline
+ strlen(cmd
.cmdline
) - 2;
931 if ((p
= strchr(cmd
.cmdline
, cmd
.key
)) != NULL
) {
939 * Process errors that occurred in temporary file operations.
942 tmperr(FILE *f
, char *ftype
)
945 fprintf(stderr
, _("%s: Read error from %s file\n"),
949 * Most likely '\0' in input.
951 fprintf(stderr
, _("%s: Unexpected EOF in %s file\n"),
954 fprintf(stderr
, _("%s: Unknown error in %s file\n"),
960 * perror()-like, but showing the program's name.
963 pgerror(int eno
, char *string
)
965 fprintf(stderr
, "%s: %s: %s\n", progname
, string
, strerror(eno
));
969 * Read the file and respond to user input.
970 * Beware: long and ugly.
973 pgfile(FILE *f
, char *name
)
975 off_t pos
, oldpos
, fpos
;
976 off_t line
= 0, fline
= 0, bline
= 0, oldline
= 0, eofline
= 0;
979 * These are the line counters:
980 * line the line desired to display
981 * fline the current line of the input file
982 * bline the current line of the file buffer
983 * oldline the line before a search was started
984 * eofline the last line of the file if it is already reached
985 * dline the line on the display
988 unsigned searchcount
= 0;
990 * Advance to EOF immediately.
994 * EOF has been reached by `line'.
998 * f and fbuf refer to the same file.
1004 char b
[READBUF
+ 1];
1007 * fbuf an exact copy of the input file as it gets read
1008 * find index table for input, one entry per line
1009 * save for the s command, to save to a file
1011 FILE *fbuf
, *find
, *save
;
1013 /* silence compiler - it may warn about longjmp() */
1022 CLOBBGRD(searchcount
);
1031 * Just copy stdin to stdout.
1033 while ((sz
= fread(b
, sizeof *b
, READBUF
, f
)) != 0)
1036 pgerror(errno
, name
);
1041 if ((fpos
= my_fseeko(f
, (off_t
)0, SEEK_SET
)) == -1)
1048 if (fbuf
== NULL
|| find
== NULL
) {
1049 fprintf(stderr
, _("%s: Cannot create tempfile\n"), progname
);
1056 rerror
= regcomp(&re
, searchfor
, REG_NOSUB
| REG_NEWLINE
);
1058 mesg(_("RE error: "));
1059 regerror(rerror
, &re
, b
, READBUF
);
1066 for (line
= startline
; ; ) {
1068 * Get a line from input file or buffer.
1071 my_fseeko(find
, line
* sizeof pos
, SEEK_SET
);
1072 if (fread(&pos
, sizeof pos
, 1, find
) == 0)
1073 tmperr(find
, "index");
1074 my_fseeko(find
, (off_t
)0, SEEK_END
);
1075 my_fseeko(fbuf
, pos
, SEEK_SET
);
1076 if (fgets(b
, READBUF
, fbuf
) == NULL
)
1077 tmperr(fbuf
, "buffer");
1078 } else if (eofline
== 0) {
1079 my_fseeko(find
, (off_t
)0, SEEK_END
);
1082 my_fseeko(fbuf
, (off_t
)0, SEEK_END
);
1083 pos
= my_ftello(fbuf
);
1084 if ((sig
= setjmp(jmpenv
)) != 0) {
1090 my_fseeko(fbuf
, pos
, SEEK_SET
);
1096 my_fseeko(f
, fpos
, SEEK_SET
);
1098 p
= fgets(b
, READBUF
, f
);
1100 if ((fpos
= my_ftello(f
)) == -1)
1101 pgerror(errno
, name
);
1104 if (p
== NULL
|| *b
== '\0') {
1106 pgerror(errno
, name
);
1113 fwrite(&pos
, sizeof pos
, 1, find
);
1117 while (*(p
= endline(ttycols
,
1120 pos
= oldpos
+ (p
- b
);
1130 } while (line
> bline
++);
1137 if (search
== FORWARD
) {
1140 search
= searchcount
= 0;
1141 mesg(_("Pattern not found"));
1147 if (regexec(&re
, b
, 0, NULL
, 0) == 0) {
1150 if (searchcount
== 0) {
1152 switch (searchdisplay
) {
1157 line
-= pagelen
/ 2 + 1;
1166 } else if (eof
) { /*
1167 * We are not searching.
1170 } else if (*b
!= '\0') {
1171 if (cflag
&& clear_screen
) {
1174 tputs(clear_screen
, 1, outcap
);
1179 if (eofline
&& line
== eofline
)
1182 if ((sig
= setjmp(jmpenv
)) != 0) {
1190 p
= endline(ttycols
, b
);
1198 if (dline
>= pagelen
|| eof
) {
1200 * Time for prompting!
1202 if (eof
&& seekeof
) {
1204 if (line
>= pagelen
)
1213 if (fline
== 0 || eflag
)
1217 prompt((line
- 1) / pagelen
+ 1);
1225 searchcount
= cmd
.count
;
1227 if (p
!= NULL
&& *p
) {
1228 if (remembered
== 1)
1230 rerror
= regcomp(&re
, p
,
1231 REG_NOSUB
| REG_NEWLINE
);
1233 mesg(_("RE error: "));
1234 sz
= regerror(rerror
, &re
,
1240 } else if (remembered
== 0) {
1241 mesg(_("No remembered search string"));
1252 searchcount
= cmd
.count
;
1254 if (p
!= NULL
&& *p
) {
1255 if (remembered
== 1)
1257 rerror
= regcomp(&re
, p
,
1258 REG_NOSUB
| REG_NEWLINE
);
1261 regerror(rerror
, &re
,
1267 } else if (remembered
== 0) {
1268 mesg("No remembered search string");
1275 my_fseeko(find
, --line
* sizeof pos
,
1277 if(fread(&pos
, sizeof pos
, 1,find
)==0)
1278 tmperr(find
, "index");
1279 my_fseeko(find
, (off_t
)0, SEEK_END
);
1280 my_fseeko(fbuf
, pos
, SEEK_SET
);
1281 if (fgets(b
, READBUF
, fbuf
) == NULL
)
1282 tmperr(fbuf
, "buffer");
1284 if (regexec(&re
, b
, 0, NULL
, 0) == 0)
1286 if (searchcount
== 0)
1291 search
= searchcount
= 0;
1292 mesg(_("Pattern not found"));
1295 eof
= search
= dline
= 0;
1297 switch (searchdisplay
) {
1302 line
-= pagelen
/ 2;
1318 while (*++p
== ' ');
1321 save
= fopen(p
, "wb");
1324 mesg(_("Cannot open "));
1327 mesg(strerror(cmd
.count
));
1333 my_fseeko(find
, (off_t
)0, SEEK_END
);
1336 my_fseeko(fbuf
,(off_t
)0,SEEK_END
);
1337 pos
= my_ftello(fbuf
);
1338 if (fgets(b
, READBUF
, f
) == NULL
) {
1344 fwrite(&pos
, sizeof pos
, 1, find
);
1348 while (*(p
= endline(ttycols
,
1351 pos
= oldpos
+ (p
- b
);
1362 my_fseeko(fbuf
, (off_t
)0, SEEK_SET
);
1363 while ((sz
= fread(b
, sizeof *b
, READBUF
,
1366 * No error check for compat.
1368 fwrite(b
, sizeof *b
, sz
, save
);
1371 my_fseeko(fbuf
, (off_t
)0, SEEK_END
);
1378 if (*cmd
.cmdline
!= 'l')
1381 cmd
.count
= 1; /* compat */
1382 if (isdigit(cuc(*cmd
.cmdline
))) {
1383 line
= cmd
.count
- 2;
1386 if (cmd
.count
!= 1) {
1387 line
+= cmd
.count
- 1
1393 * Nothing to do if count==1.
1399 * Half screen forward.
1401 case '\004': /* ^D */
1402 if (*cmd
.cmdline
!= cmd
.key
)
1405 cmd
.count
= 1; /* compat */
1406 line
+= (cmd
.count
* pagelen
/ 2)
1416 cmd
.count
= 1; /* compat */
1417 line
+= cmd
.count
* pagelen
- 2;
1420 if (*cmd
.cmdline
!= 'f')
1424 if (eofline
&& line
>= eofline
)
1431 * Just a number, or '-', or <newline>.
1434 cmd
.count
= 1; /* compat */
1435 if (isdigit(cuc(*cmd
.cmdline
)))
1436 line
= (cmd
.count
- 1) * pagelen
- 2;
1438 line
+= (cmd
.count
- 1)
1439 * (pagelen
- 1) - 2;
1440 if (*cmd
.cmdline
!= '\0')
1442 if (cmd
.count
!= 1) {
1462 case '\014': /* ^L */
1467 if (line
>= pagelen
)
1479 mesg(_(": !command not allowed in "
1484 write(1, cmd
.cmdline
,
1485 strlen(cmd
.cmdline
));
1487 my_sigset(SIGINT
, SIG_IGN
);
1488 my_sigset(SIGQUIT
, SIG_IGN
);
1489 switch (cpid
= fork()) {
1491 p
= getenv("SHELL");
1492 if (p
== NULL
) p
= "/bin/sh";
1496 if (isatty(0) == 0) {
1498 open(tty
, O_RDONLY
);
1502 my_sigset(SIGINT
, oldint
);
1503 my_sigset(SIGQUIT
, oldquit
);
1504 my_sigset(SIGTERM
, oldterm
);
1506 cmd
.cmdline
+ 1, NULL
);
1511 mesg(_("fork() failed, "
1512 "try again later\n"));
1515 while (wait(NULL
) != cpid
);
1517 my_sigset(SIGINT
, sighandler
);
1518 my_sigset(SIGQUIT
, sighandler
);
1526 write(1, copyright
+ 4, strlen(copyright
+ 4));
1527 write(1, helpscreen
, strlen(helpscreen
));
1535 nextfile
= cmd
.count
;
1548 nextfile
= 0 - cmd
.count
;
1569 if (*cmd
.cmdline
!= cmd
.key
)
1570 pagelen
= ++cmd
.count
;
1578 if (cflag
&& dline
== 1) {
1592 main(int argc
, char **argv
)
1598 progname
= basename(argv
[0]);
1600 setlocale(LC_MESSAGES
, "");
1601 bindtextdomain(PACKAGE
, LOCALEDIR
);
1602 textdomain(PACKAGE
);
1604 if (tcgetattr(1, &otio
) == 0) {
1606 oldint
= my_sigset(SIGINT
, sighandler
);
1607 oldquit
= my_sigset(SIGQUIT
, sighandler
);
1608 oldterm
= my_sigset(SIGTERM
, sighandler
);
1609 setlocale(LC_CTYPE
, "");
1610 setlocale(LC_COLLATE
, "");
1612 setupterm(NULL
, 1, &tinfostat
);
1614 helpscreen
= _(helpscreen
);
1616 for (arg
= 1; argv
[arg
]; arg
++) {
1617 if (*argv
[arg
] == '+')
1619 if (*argv
[arg
] != '-' || argv
[arg
][1] == '\0')
1622 for (i
= 1; argv
[arg
][i
]; i
++) {
1623 switch (argv
[arg
][i
]) {
1625 if (i
!= 1 || argv
[arg
][i
+ 1])
1626 invopt(&argv
[arg
][i
]);
1628 case '1': case '2': case '3': case '4': case '5':
1629 case '6': case '7': case '8': case '9': case '0':
1630 pagelen
= atoi(argv
[arg
] + i
);
1646 if (argv
[arg
][i
+ 1]) {
1647 pstring
= &argv
[arg
][i
+ 1];
1648 } else if (argv
[++arg
]) {
1650 pstring
= argv
[arg
];
1661 invopt(&argv
[arg
][i
]);
1668 for (arg
= 1; argv
[arg
]; arg
++) {
1669 if (*argv
[arg
] == '-') {
1670 if (argv
[arg
][1] == '-') {
1674 if (argv
[arg
][1] == '\0')
1676 if (argv
[arg
][1] == 'p' && argv
[arg
][2] == '\0')
1680 if (*argv
[arg
] != '+')
1683 switch (*(argv
[arg
] + 1)) {
1687 case '1': case '2': case '3': case '4': case '5':
1688 case '6': case '7': case '8': case '9': case '0':
1689 startline
= atoi(argv
[arg
] + 1);
1692 searchfor
= argv
[arg
] + 2;
1693 if (*searchfor
== '\0')
1695 p
= searchfor
+ strlen(searchfor
) - 1;
1696 if (*p
== '/') *p
= '\0';
1697 if (*searchfor
== '\0')
1705 pgfile(stdin
, "stdin");
1708 files
.last
= arg
+ argc
- 1;
1709 for ( ; argv
[arg
]; arg
+= nextfile
) {
1711 files
.current
= arg
;
1713 static int firsttime
;
1715 if (firsttime
> 1) {
1716 mesg(_("(Next file: "));
1729 nextfile
= cmd
.count
;
1742 nextfile
= 0 - cmd
.count
;
1756 if (strcmp(argv
[arg
], "-") == 0)
1759 input
= fopen(argv
[arg
], "r");
1760 if (input
== NULL
) {
1761 pgerror(errno
, argv
[arg
]);
1766 if (ontty
== 0 && argc
> 2) {
1768 * Use the prefix as specified by SUSv2.
1770 write(1, "::::::::::::::\n", 15);
1771 write(1, argv
[arg
], strlen(argv
[arg
]));
1772 write(1, "\n::::::::::::::\n", 16);
1774 pgfile(input
, argv
[arg
]);