bug#47243: pr lacks -p

Collin Funk <[email protected]>
Newsgroups gmane.comp.gnu.core-utils.bugs
Message-ID <[email protected]>
Hi Paul,

Paul Eggert <[email protected]> writes:

> Thanks for looking into that. Unfortunately POSIX says -p should be
> ignored only if standard output is a terminal, and that newline should
> be read from /dev/tty, not from standard input. This is so that users
> can pipe into 'pr -p'. So the proposed patch needs some changes. Here
> are the issues I found:

Thanks for the thorough review.

I think that v3 attached should cover everything.

Collin
v3-0001-pr-implement-p-as-required-by-POSIX-Issue-6.patch (text/x-patch, 5.9 KB)
From 79dc6d5cfbc45966cd039a599c7db372452b1a9a Mon Sep 17 00:00:00 2001
Message-ID: <79dc6d5cfbc45966cd039a599c7db372452b1a9a.1753669052.git.collin.funk1@gmail.com>
From: Collin Funk <[email protected]>
Date: Sun, 27 Jul 2025 15:00:15 -0700
Subject: [PATCH v3] pr: implement '-p' as required by POSIX Issue 6

* src/pr.c (pause_option): New variable.
(tty_fp): Likewise.
(short_options): Add '-p'.
(long_options): Add '--pause'.
(main): Add the option. Ignore it if standard output is not a tty. Open
a 'FILE *' for /dev/tty and fail if any operations on it are
unsuccessful.
(print_files): If the option is use emit '\a' to stderr and wait until a
newline is read to print the next page.
(usage): Mention the new option.
* doc/coreutils.texi (pr invocation): Document the new option.
* NEWS: Mention the new option.
---
 NEWS               |  4 ++++
 doc/coreutils.texi |  8 +++++++
 src/pr.c           | 55 +++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 64 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index 0b2be7116..776932c69 100644
--- a/NEWS
+++ b/NEWS
@@ -64,6 +64,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   Iranian locale (fa_IR) and for the Ethiopian locale (am_ET), and also
   does so more consistently for the Thailand locale (th_TH.UTF-8).
 
+  pr now supports the -p option, to pause upon printing each page until
+  a newline character is read from /dev/tty, as required by POSIX Issue
+  6.  The corresponding long option is --pause.
+
 
 * Noteworthy changes in release 9.7 (2025-04-09) [stable]
 
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 7ca5b222c..a8193f5ff 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -2825,6 +2825,14 @@ @node pr invocation
 set with the @option{-W/-w} option.  A limited overflow may occur with
 numbered single column output (compare @option{-n} option).
 
+@item -p
+@itemx --pause
+@opindex -p
+@opindex --pause
+After printing each page, print an alert (bell) to standard error and
+wait for a newline to be read from @file{/dev/tty} before printing the
+next page.  This option is ignored unless standard output is a tty.
+
 @item -r
 @itemx --no-file-warnings
 @opindex -r
diff --git a/src/pr.c b/src/pr.c
index e7081a059..22e752675 100644
--- a/src/pr.c
+++ b/src/pr.c
@@ -711,6 +711,12 @@ static char *custom_header;
 /* (-D) Date format for the header.  */
 static char const *date_format;
 
+/* If true, pause after each page until a newline is read from /dev/tty.  */
+static bool pause_option;
+
+/* Used to read from /dev/tty if --p/--pause is in use.  */
+static FILE *tty_fp;
+
 /* The local time zone rules, as per the TZ environment variable.  */
 static timezone_t localtz;
 
@@ -738,7 +744,7 @@ enum
 };
 
 static char const short_options[] =
-  "-0123456789D:FJN:S::TW:abcde::fh:i::l:mn::o:rs::tvw:";
+  "-0123456789D:FJN:S::TW:abcde::fh:i::l:mn::po:rs::tvw:";
 
 static struct option const long_options[] =
 {
@@ -758,6 +764,7 @@ static struct option const long_options[] =
   {"number-lines", optional_argument, nullptr, 'n'},
   {"first-line-number", required_argument, nullptr, 'N'},
   {"indent", required_argument, nullptr, 'o'},
+  {"pause", no_argument, nullptr, 'p'},
   {"no-file-warnings", no_argument, nullptr, 'r'},
   {"separator", optional_argument, nullptr, 's'},
   {"sep-string", optional_argument, nullptr, 'S'},
@@ -999,6 +1006,9 @@ main (int argc, char **argv)
           chars_per_margin = getoptnum (optarg, 0,
                                         _("'-o MARGIN' invalid line offset"));
           break;
+        case 'p':
+          pause_option = true;
+          break;
         case 'r':
           ignore_failed_opens = true;
           break;
@@ -1079,6 +1089,18 @@ main (int argc, char **argv)
     error (EXIT_FAILURE, 0,
            _("cannot specify both printing across and printing in parallel"));
 
+  if (pause_option)
+    {
+      pause_option = isatty (STDOUT_FILENO);
+      if (pause_option)
+        {
+          tty_fp = fopen ("/dev/tty", "r");
+          if (tty_fp == nullptr)
+            error (EXIT_FAILURE, errno, _("cannot open %s for reading"),
+                   quoteaf ("/dev/tty"));
+        }
+    }
+
 /* Translate some old short options to new/long options.
    To meet downward compatibility with other UNIX pr utilities
    and some POSIX specifications. */
@@ -1149,6 +1171,8 @@ main (int argc, char **argv)
 
   if (have_read_stdin && fclose (stdin) == EOF)
     error (EXIT_FAILURE, errno, _("standard input"));
+  if (pause_option && fclose (tty_fp) == EOF)
+    error (EXIT_FAILURE, errno, "%s", quotef ("/dev/tty"));
   main_exit (failed_opens ? EXIT_FAILURE : EXIT_SUCCESS);
 }
 
@@ -1636,8 +1660,31 @@ print_files (int number_of_files, char **av)
   init_funcs ();
 
   line_number = line_count;
-  while (print_page ())
-    ;
+  for (;;)
+    {
+      if (pause_option)
+        {
+          if (putc ('\a', stderr) == EOF || fflush (stderr) != 0)
+            write_error ();
+          for (;;)
+            {
+              int ch = getc (tty_fp);
+              if (ch == EOF)
+                {
+                  /* Just exit if the user presses Ctrl-D.  */
+                  if (feof (tty_fp))
+                    goto finish;
+                  error (EXIT_FAILURE, errno, _("error reading %s"),
+                         quoteaf ("/dev/tty"));
+                }
+              if (ch == '\n')
+                break;
+            }
+        }
+      if (! print_page ())
+        break;
+    }
+ finish:
 }
 
 /* Initialize header information.
@@ -2824,6 +2871,8 @@ Paginate or columnate FILE(s) for printing.\n\
   -o, --indent=MARGIN\n\
                     offset each line with MARGIN (zero) spaces, do not\n\
                     affect -w or -W, MARGIN will be added to PAGE_WIDTH\n\
+  -p, --pause       pause at the beginning of each page until a newline\n\
+                    is read from /dev/tty.\n\
   -r, --no-file-warnings\n\
                     omit warning when a file cannot be opened\n\
 "), stdout);
-- 
2.50.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.