Hi! After seeing the diff for cat -n earlier today, and just browsing Unix stuff on my own, I noticed OpenBSD's pr(1) command has no -p option despite pr.1 stating: > The pr utility is compliant with the IEEE Std 1003.1-2008 ("POSIX.1") > specification. https://man.openbsd.org/pr.1 This part of the man page was added in this diff: https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/pr/pr.1.diff?r1=1.16&r2=1.17 https://github.com/openbsd/src/commit/7c5a075bb35c9874ed6ed8040f78870dae704a20 and was never correct. -p has been a mandatory (it's neither XSI nor optional) part of POSIX since 2001. It's also not merely a SysVism or POSIXism, as -p exists in Unix 8th and 10th editions: http://man.cat-v.org/unix_8th/1/pr http://man.cat-v.org/unix_10th/1/pr
In case the -p option is not desired, I have a small diff attached (no-p.txt) that fixes the man page, and fixes a typo in pr.c But I also have a bigger diff (pr-p.txt) adding -p to pr. It's inspired by the FreeBSD and NetBSD diffs, but mostly the NetBSD one: https://github.com/freebsd/freebsd/commit/cace3f9d081619c267182e7e1c926cafabc283e2 https://svnweb.freebsd.org/base?view=revision&revision=93481 https://github.com/NetBSD/src/commit/a19c45064f8d362783a3e36c2820544bc05d644a http://cvsweb.netbsd.org/bsdweb.cgi/src/usr.bin/pr/pr.c I did not touch -f or -F, though those can easily be changed later if desired. I also did not touch -n and its numbering limit. Implementation note: while POSIX says a "<carriage-return>", i.e. '\r', should be waited for, FreeBSD, NetBSD, OpenSolaris, and Unix 10th edition wait for '\n' and I followed them rather than POSIX. It would be easy to make pr wait for either '\n' or '\r' though. I don't know whether to add a new date or name to the copyright/license text at the top. A whole new flag was added, but it's adapted from another implementation. I mostly imitated pr's pre-existing non-style(9) style, except for using proper style(9) inside the new prpause() function. Thanks for reading!
Index: pr.1 =================================================================== RCS file: /cvs/src/usr.bin/pr/pr.1,v retrieving revision 1.27 diff -u -p -r1.27 pr.1 --- pr.1 4 Jun 2014 07:57:27 -0000 1.27 +++ pr.1 11 Dec 2020 23:33:33 -0000 @@ -310,12 +310,6 @@ operand is .Xr more 1 , .Xr ascii 7 .Sh STANDARDS -The -.Nm -utility is compliant with the -.St -p1003.1-2008 -specification. -.Pp The flag .Op Fl f is marked by Index: pr.c =================================================================== RCS file: /cvs/src/usr.bin/pr/pr.c,v retrieving revision 1.43 diff -u -p -r1.43 pr.c --- pr.c 22 Jan 2020 07:52:37 -0000 1.43 +++ pr.c 11 Dec 2020 23:33:33 -0000 @@ -64,7 +64,7 @@ * pr: more boundary conditions than a four-legged porcupine * * the original version didn't support form-feeds, while many of the ad-hoc - * pr implementations out there do. Addding this and making it work reasonably + * pr implementations out there do. Adding this and making it work reasonably * in all four output modes required quite a bit of hacking and a few minor * bugs were noted and fixed in the process. Some implementations have this * as the as -f, some as -F so we accept either.
Index: extern.h =================================================================== RCS file: /cvs/src/usr.bin/pr/extern.h,v retrieving revision 1.6 diff -u -p -r1.6 extern.h --- extern.h 19 Jan 2015 15:30:52 -0000 1.6 +++ extern.h 12 Dec 2020 02:42:34 -0000 @@ -50,6 +50,7 @@ int onecol(int, char **); int otln(char *, int, int *, int *, int); void pfail(void); int prhead(char *, char *, int); +void prpause(int); int prtail(int, int); int setup(int, char **); void terminate(int); Index: pr.1 =================================================================== RCS file: /cvs/src/usr.bin/pr/pr.1,v retrieving revision 1.27 diff -u -p -r1.27 pr.1 --- pr.1 4 Jun 2014 07:57:27 -0000 1.27 +++ pr.1 12 Dec 2020 02:42:34 -0000 @@ -33,7 +33,7 @@ .\" .\" from: @(#)pr.1 8.1 (Berkeley) 6/6/93 .\" -.Dd $Mdocdate: June 4 2014 $ +.Dd $Mdocdate: December 11 2020 $ .Dt PR 1 .Os .Sh NAME @@ -43,7 +43,7 @@ .Nm pr .Op Cm + Ns Ar page .Op Fl Ar column -.Op Fl adFfmrt +.Op Fl adFfmprt .Op Fl e Ns Oo Ar char Oc Ns Op Ar gap .Op Fl h Ar header .Op Fl i Ns Oo Ar char Oc Ns Op Ar gap @@ -256,6 +256,9 @@ If the .Fl o option is not specified, the default is zero. The space taken is in addition to the output line width. +.It Fl p +Pause before beginning each page if the standard output is a terminal, ring the bell, and wait for a newline on +.Pa /dev/tty .It Fl r Write no diagnostic reports on failure to open a file. .It Fl s Ns Op Ar char Index: pr.c =================================================================== RCS file: /cvs/src/usr.bin/pr/pr.c,v retrieving revision 1.43 diff -u -p -r1.43 pr.c --- pr.c 22 Jan 2020 07:52:37 -0000 1.43 +++ pr.c 12 Dec 2020 02:42:34 -0000 @@ -64,7 +64,7 @@ * pr: more boundary conditions than a four-legged porcupine * * the original version didn't support form-feeds, while many of the ad-hoc - * pr implementations out there do. Addding this and making it work reasonably + * pr implementations out there do. Adding this and making it work reasonably * in all four output modes required quite a bit of hacking and a few minor * bugs were noted and fixed in the process. Some implementations have this * as the as -f, some as -F so we accept either. @@ -123,16 +123,19 @@ int nodiag; /* do not report file open char schar; /* text column separation character */ int sflag; /* -s option for multiple columns */ int nohead; /* do not write head and trailer */ +int pgpause; /* pause before each page */ int pgwd; /* page width with multiple col output */ /* * misc globals */ volatile sig_atomic_t ferr; /* error message delayed */ +int ttyout; /* output is a tty */ int addone = 0; /* page length is odd with double space */ int errcnt = 0; /* error count on file processing */ int beheaded = 0; /* header / trailer link */ char digs[] = "0123456789"; /* page number translation map */ +FILE *ttyinf; /* input terminal for page pauses */ int main(int argc, char *argv[]) @@ -258,8 +261,13 @@ onecol(int argc, char *argv[]) rc = inln(inf,lbuf,LBUF,&cnt,&cps,0,&mor); if (cnt >= 0) { if (!lrgln) - if (!linecnt && prhead(hbuf, fname, ++pagecnt)) - goto out; + if (!linecnt) { + if (pgpause) + prpause(pagecnt+1); + + if (prhead(hbuf, fname, ++pagecnt)) + goto out; + } /* * start new line or continue a long one @@ -541,6 +549,8 @@ vertcol(int argc, char *argv[]) * print header iff we got anything on the first read */ if (vc[0].cnt >= 0) { + if (pgpause) + prpause(pagecnt+1); if (prhead(hbuf, fname, ++pagecnt)) goto out; @@ -751,8 +761,13 @@ horzcol(int argc, char *argv[]) */ rc = inln(inf,ptbf,colwd,&cnt,&cps,1, &mor); if (cnt >= 0) { - if (!i && !j && prhead(hbuf, fname, ++pagecnt)) - goto out; + if (!i && !j) { + if (pgpause) + prpause(pagecnt+1); + + if (prhead(hbuf, fname, ++pagecnt)) + goto out; + } ptbf += cnt; lstdat = ptbf; @@ -1075,8 +1090,13 @@ mulfile(int argc, char *argv[]) * if there was anything to do, print it */ if (fproc != 0) { - if (!i && prhead(hbuf, fname, ++pagecnt)) - goto out; + if (!i) { + if (pgpause) + prpause(pagecnt+1); + + if (prhead(hbuf, fname, ++pagecnt)) + goto out; + } /* * output line @@ -1619,6 +1639,32 @@ prhead(char *buf, char *fname, int pagcn } /* + * prpause(): pause before printing each page + * + * pagcnt page number + */ +void +prpause(int pagcnt) +{ + if (ttyout) { + int c; + + putc('\a', stderr); + fflush(stderr); + + while ((c = getc(ttyinf)) != '\n' && c != EOF) + ; + + /* + * Pause ONLY before first page of first file. + * This would be used in order to pause ONLY before first page of first file to support an XSI-style -f option, but is currently a no-op. + */ + if (pgpause == FIRSTPAGE && pagcnt == 1) + pgpause = NO_PAUSE; + } +} + +/* * prtail(): pad page with empty lines (if required) and print page trailer * if requested * @@ -1741,7 +1787,7 @@ void usage(void) { ferrout( - "usage: pr [+page] [-column] [-adFfmrt] [-e[char][gap]] [-h header]\n"); + "usage: pr [+page] [-column] [-adFfmprt] [-e[char][gap]] [-h header]\n"); ferrout( "\t[-i[char][gap]] [-l lines] [-n[char][width]] [-o offset] [-s[char]]\n"); ferrout( @@ -1762,10 +1808,14 @@ setup(int argc, char *argv[]) int cflag = 0; const char *errstr; - if (isatty(fileno(stdout))) + ttyinf = stdin; + + if (isatty(fileno(stdout))) { ferr = 1; + ttyout = 1; + } - while ((c = egetopt(argc, argv, "#adfFmrte?h:i?l:n?o:s?w:")) != -1) { + while ((c = egetopt(argc, argv, "#adfFmprte?h:i?l:n?o:s?w:")) != -1) { switch (c) { case '+': pgnm = strtonum(eoptarg, 1, INT_MAX, &errstr); @@ -1871,6 +1921,9 @@ setup(int argc, char *argv[]) return(1); } break; + case 'p': + pgpause |= EACHPAGE; + break; case 'r': nodiag = 1; break; @@ -1982,6 +2035,17 @@ setup(int argc, char *argv[]) if (lines & 1) ++addone; lines /= 2; + } + } + + /* + * Open /dev/tty if we are to pause before each page, + * but only if stdout is a terminal and stdin is not a terminal. + */ + if (ttyout && pgpause && !isatty(fileno(stdin))) { + if ((ttyinf = fopen("/dev/tty", "r")) == NULL) { + ferrout("pr: cannot open terminal\n"); + return (1); } } Index: pr.h =================================================================== RCS file: /cvs/src/usr.bin/pr/pr.h,v retrieving revision 1.5 diff -u -p -r1.5 pr.h --- pr.h 19 Jan 2015 15:30:52 -0000 1.5 +++ pr.h 12 Dec 2020 02:42:34 -0000 @@ -70,6 +70,14 @@ #define NORMAL 0 /* + * Which pages to pause before (for -p option, and for a potential XSI-style -f option) + */ +#define NO_PAUSE 0 +#define FIRSTPAGE 1 +#define ENSUINGPAGES 2 +#define EACHPAGE (FIRSTPAGE | ENSUINGPAGES) + +/* * structure for vertical columns. Used to balance cols on last page */ struct vcol {