bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

pr page-number fixes


From: Paul Eggert
Subject: pr page-number fixes
Date: Fri, 12 Nov 2004 11:42:47 -0800
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux)

Partly in response to today's minutes from the Open Group
interpretations meeting, and partly to remove a 2**31 limit in "pr"
that should be a 2**64 limit, I installed this:

2004-11-12  Paul Eggert  <address@hidden>

        * NEWS: Document the following change.
        * src/pr.c (strtoumax): Declare if not declared.
        (skip_to_page, first_page_number, last_page_number, page_number,
        first_last_page, print_header):
        Use uintmax_t for page numbers.
        (first_last_page): Remove unnecessary forward declaration.
        Do not modify arg (it is now a const pointer).
        Return a true if successful, false (without print a diagnostic)
        otherwise.
        (main): If +XXX does not specify a valid page range, treat it
        as a file name.  This follows the response to Open Group XCU ERN 41
        
<http://www.opengroup.org/sophocles/show_mail.tpl?source=L&listname=austin-group-l&id=7717>,
        which says the behavior is allowed.
        (skip_to_page): When starting page number exceeds page count,
        print both numbers in the diagnostic.
        (print_header): Detect page number overflow.

Index: NEWS
===================================================================
RCS file: /fetish/cu/NEWS,v
retrieving revision 1.246
diff -p -u -r1.246 NEWS
--- NEWS        30 Oct 2004 00:05:00 -0000      1.246
+++ NEWS        12 Nov 2004 19:34:38 -0000
@@ -84,6 +84,11 @@ GNU coreutils NEWS                      
   pathchk no longer accepts trailing options, e.g., "pathchk -p foo -b"
   now treats -b as a file name to check, not as an invalid option.
 
+  pr now supports page numbers up to 2**64 on most hosts, and it
+  detects page number overflow instead of silently wrapping around.
+  pr now accepts file names that begin with "+" so long as the rest of
+  the file name does not look like a page range.
+
   printf has several changes:
 
     It now uses 'intmax_t' (not 'long int') to format integers, so it
Index: src/pr.c
===================================================================
RCS file: /fetish/cu/src/pr.c,v
retrieving revision 1.121
diff -p -u -r1.121 pr.c
--- src/pr.c    21 Sep 2004 22:26:42 -0000      1.121
+++ src/pr.c    12 Nov 2004 19:34:38 -0000
@@ -321,6 +321,10 @@
 #include "posixver.h"
 #include "xstrtol.h"
 
+#if ! (HAVE_DECL_STRTOUMAX || defined strtoumax)
+uintmax_t strtoumax ();
+#endif
+
 /* The official name of this program (e.g., no `g' prefix).  */
 #define PROGRAM_NAME "pr"
 
@@ -418,7 +422,7 @@ static bool read_line (COLUMN *p);
 static bool print_page (void);
 static bool print_stored (COLUMN *p);
 static bool open_file (char *name, COLUMN *p);
-static bool skip_to_page (int page);
+static bool skip_to_page (uintmax_t page);
 static void print_header (void);
 static void pad_across_to (int position);
 static void add_line_number (COLUMN *p);
@@ -439,7 +443,6 @@ static void read_rest_of_line (COLUMN *p
 static void skip_read (COLUMN *p, int column_number);
 static void print_char (char c);
 static void cleanup (void);
-static void first_last_page (char *pages);
 static void print_sep_string (void);
 static void separator_string (const char *optarg_S);
 
@@ -609,14 +612,14 @@ static int columns = 1;
 
 /* (+NNN:MMM) Page numbers on which to begin and stop printing.
    first_page_number = 0  will be used to check input only. */
-static int first_page_number = 0;
-static int last_page_number = 0;
+static uintmax_t first_page_number = 0;
+static uintmax_t last_page_number = UINTMAX_MAX;
 
 /* Number of files open (not closed, not on hold). */
 static int files_ready_to_read = 0;
 
 /* Current page number.  Displayed in header. */
-static int page_number;
+static uintmax_t page_number;
 
 /* Current line number.  Displayed when -n flag is specified.
 
@@ -794,45 +797,39 @@ cols_ready_to_print (void)
 /* Estimate first_ / last_page_number
    using option +FIRST_PAGE:LAST_PAGE */
 
-static void
-first_last_page (char *pages)
+static bool
+first_last_page (char const *pages)
 {
-  char *str1;
+  char *p;
+  uintmax_t first;
+  uintmax_t last = UINTMAX_MAX;
+  int err;
+
+  errno = 0;
+  first = strtoumax (pages, &p, 10);
+  err = errno;
+  if (p == pages || !first)
+    return false;
 
-  if (*pages == ':')
+  if (*p == ':')
     {
-      error (0, 0, _("`--pages' invalid range of page numbers: `%s'"), pages);
-      usage (EXIT_FAILURE);
+      char const *p1 = p + 1;
+      errno = 0;
+      last = strtoumax (p1, &p, 10);
+      err |= errno;
+      if (p1 == p || last < first)
+       return false;
     }
 
-  str1 = strchr (pages, ':');
-  if (str1 != NULL)
-    *str1 = '\0';
+  if (*p)
+    return false;
 
-  {
-    long int tmp_long;
-    if (xstrtol (pages, NULL, 10, &tmp_long, "") != LONGINT_OK
-       || tmp_long < 1 || tmp_long > INT_MAX)
-      error (EXIT_FAILURE, 0, _("`--pages' invalid starting page number: 
`%s'"),
-            pages);
-    first_page_number = tmp_long;
-  }
+  if (err)
+    error (EXIT_FAILURE, err, _("Page range `%s'"), pages);
 
-  if (str1 == NULL)
-    return;
-
-  {
-    long int tmp_long;
-    if (xstrtol (str1 + 1, NULL, 10, &tmp_long, "") != LONGINT_OK
-       || tmp_long <= 0 || tmp_long > INT_MAX)
-      error (EXIT_FAILURE, 0, _("`--pages' invalid ending page number: `%s'"),
-            str1 + 1);
-    last_page_number = tmp_long;
-  }
-
-  if (first_page_number > last_page_number)
-    error (EXIT_FAILURE, 0,
-       _("`--pages' starting page number is larger than ending page number"));
+  first_page_number = first;
+  last_page_number = last;
+  return true;
 }
 
 /* Estimate length of col_sep_string with option -S.  */
@@ -889,23 +886,19 @@ main (int argc, char **argv)
       switch (c)
        {
        case 1:                 /* Non-option argument. */
-         if (*optarg == '+')
-           {
-             /* long option --page dominates old `+FIRST_PAGE ...' */
-             if (first_page_number <= 0 && last_page_number <= 0)
-               first_last_page (optarg);
-           }
-         else
+         /* long option --page dominates old `+FIRST_PAGE ...'.  */
+         if (! (first_page_number == 0
+                && *optarg == '+' && first_last_page (optarg + 1)))
            file_names[n_files++] = optarg;
          break;
 
        case PAGES_OPTION:      /* --pages=FIRST_PAGE[:LAST_PAGE] */
          {                     /* dominates old opt +... */
-           if (optarg)
-             first_last_page (optarg);
-           else
+           if (! optarg)
              error (EXIT_FAILURE, 0,
                     _("`--pages=FIRST_PAGE[:LAST_PAGE]' missing argument"));
+           else if (! first_last_page (optarg))
+             error (EXIT_FAILURE, 0, _("Invalid page range `%s'"), optarg);
            break;
          }
 
@@ -1875,7 +1868,7 @@ print_page (void)
       print_a_FF = false;
     }
 
-  if (last_page_number && page_number > last_page_number)
+  if (last_page_number < page_number)
     return false;              /* Stop printing with LAST_PAGE */
 
   reset_status ();             /* Change ON_HOLD to OPEN. */
@@ -2325,9 +2318,11 @@ print_char (char c)
    PAGE may be larger than total number of pages. */
 
 static bool
-skip_to_page (int page)
+skip_to_page (uintmax_t page)
 {
-  int n, i, j;
+  uintmax_t n;
+  int i;
+  int j;
   COLUMN *p;
 
   for (n = 1; n < page; ++n)
@@ -2356,8 +2351,9 @@ skip_to_page (int page)
          /* It's very helpful, normally the total number of pages is
             not known in advance.  */
          error (0, 0,
-            _("starting page number larger than total number of pages: `%d'"),
-                n);
+                _("starting page number %"PRIuMAX
+                  " exceeds page count %"PRIuMAX),
+                page, n);
           break;
        }
     }
@@ -2372,7 +2368,7 @@ skip_to_page (int page)
 static void
 print_header (void)
 {
-  char page_text[256 + INT_STRLEN_BOUND (int)];
+  char page_text[256 + INT_STRLEN_BOUND (page_number)];
   int available_width;
   int lhs_spaces;
   int rhs_spaces;
@@ -2384,10 +2380,13 @@ print_header (void)
   pad_across_to (chars_per_margin);
   print_white_space ();
 
+  if (page_number == 0)
+    error (EXIT_FAILURE, 0, _("Page number overflow"));
+
   /* The translator must ensure that formatting the translation of
-     "Page %d" does not generate more than (sizeof page_text - 1)
+     "Page %"PRIuMAX does not generate more than (sizeof page_text - 1)
      bytes.  */
-  sprintf (page_text, _("Page %d"), page_number++);
+  sprintf (page_text, _("Page %"PRIuMAX), page_number++);
   available_width = header_width_available - mbswidth (page_text, 0);
   available_width = MAX (0, available_width);
   lhs_spaces = available_width >> 1;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]