summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pr.c173
1 files changed, 72 insertions, 101 deletions
diff --git a/src/pr.c b/src/pr.c
index 8681957e9..5c5b96a1b 100644
--- a/src/pr.c
+++ b/src/pr.c
@@ -1,5 +1,5 @@
/* pr -- convert text files for printing.
- Copyright (C) 88, 91, 1995-2000 Free Software Foundation, Inc.
+ Copyright (C) 88, 91, 1995-2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -150,6 +150,8 @@
-d, --double-space Double space the output.
+ -D FORMAT, --date-format=FORMAT Use FORMAT for the header date.
+
-e[CHAR[WIDTH]], --expand-tabs[=CHAR[WIDTH]]
Expand tabs to spaces on input. Optional argument CHAR
is the input TAB character. (Default is TAB). Optional
@@ -162,12 +164,7 @@
-h HEADER, --header=HEADER
Replace the filename in the header with the string HEADER.
- Checking and left-hand-side truncation of the length of the
- standard and custom header string. A centered header is used.
- The format of date and time has been shortened
- to yyyy-mm-dd HH:MM to give place to a maximal filename
- information.
- -h "" now prints a blank line header. -h"" shows an error.
+ A centered header is used.
-i[CHAR[WIDTH]], --output-tabs[=CHAR[WIDTH]]
Replace spaces with tabs on output. Optional argument
@@ -320,6 +317,7 @@
#include "system.h"
#include "closeout.h"
#include "error.h"
+#include "mbswidth.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no `g' prefix). */
@@ -506,10 +504,6 @@ static int print_a_FF = FALSE;
to print after it. */
static int print_a_header;
-/* (-h) True means we're using the standard header rather than a
- customized one specified by the -h flag. */
-static int standard_header = TRUE;
-
/* (-f) True means use formfeeds instead of newlines to separate pages. */
static int use_form_feed = FALSE;
@@ -711,8 +705,15 @@ static int pad_vertically;
/* (-h) String of characters used in place of the filename in the header. */
static char *custom_header;
-/* String containing the date, filename or custom header, and "Page ". */
-static char *header;
+/* (-D) Date format for the header. */
+static char const *date_format;
+
+/* Date and file name for the header. */
+static char *date_text;
+static char const *file_text;
+
+/* Output columns available, not counting the date and file name. */
+static int header_width_available;
static int *clump_buff;
@@ -722,10 +723,6 @@ static int *clump_buff;
structure COLUMN. */
static int last_line = FALSE;
-/* If nonzero, print a non-variable date and time with the header
- -h HEADER using pr test-suite */
-static int test_suite;
-
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
@@ -736,12 +733,12 @@ enum
static struct option const long_options[] =
{
- {"test", no_argument, &test_suite, 1},
{"pages", required_argument, NULL, PAGES_OPTION},
{"columns", required_argument, NULL, COLUMNS_OPTION},
{"across", no_argument, NULL, 'a'},
{"show-control-chars", no_argument, NULL, 'c'},
{"double-space", no_argument, NULL, 'd'},
+ {"date-format", required_argument, NULL, 'D'},
{"expand-tabs", optional_argument, NULL, 'e'},
{"form-feed", no_argument, NULL, 'f'},
{"header", required_argument, NULL, 'h'},
@@ -862,7 +859,7 @@ main (int argc, char **argv)
: NULL);
while ((c = getopt_long (argc, argv,
- "-0123456789abcde::fFh:i::Jl:mn::N:o:rs::S::tTvw:W:",
+ "-0123456789abcdD:e::fFh:i::Jl:mn::N:o:rs::S::tTvw:W:",
long_options, NULL))
!= -1)
{
@@ -932,6 +929,9 @@ main (int argc, char **argv)
case 'd':
double_space = TRUE;
break;
+ case 'D':
+ date_format = optarg;
+ break;
case 'e':
if (optarg)
getoptarg (optarg, 'e', &input_tab_char,
@@ -945,7 +945,6 @@ main (int argc, char **argv)
break;
case 'h':
custom_header = optarg;
- standard_header = FALSE;
break;
case 'i':
if (optarg)
@@ -1065,6 +1064,11 @@ main (int argc, char **argv)
}
}
+ if (! date_format)
+ date_format = (getenv ("POSIXLY_CORRECT")
+ ? dcgettext (NULL, "%b %e %H:%M %Y", LC_TIME)
+ : "%Y-%m-%d %H:%M");
+
/* Now we can set a reasonable initial value: */
if (first_page_number == 0)
first_page_number = 1;
@@ -1624,90 +1628,47 @@ print_files (int number_of_files, char **av)
;
}
-/* Estimate the number of characters taken up by a short format date and
- time: "yy-mm-dd HH:MM" and: "Page NNNN". */
-#define CHARS_FOR_DATE_AND_PAGE 25
-
-#define T_BUF_FMT "%Y-%m-%d %H:%M" /* date/time short format */
-
-/* Add `2' because the expansion of %Y occupies 4 bytes, which is two more
- than the length of `%Y'. Each of the other formats expand to two bytes. */
-#define T_BUF_SIZE (2 + sizeof T_BUF_FMT)
-
-/* This string is exactly the same length as the expansion of T_BUF_FMT. */
-#define NO_DATE "-- Date/Time -- "
-
/* Initialize header information.
If DESC is non-negative, it is a file descriptor open to
- FILENAME for reading.
-
- Allocate space for a header string,
- Determine the time, insert file name or user-specified string.
- Make use of a centered header with left-hand-side truncation marked by
- a '*` in front, if necessary. */
+ FILENAME for reading. */
static void
init_header (char *filename, int desc)
{
- char *f = filename;
+ char *buf;
+ char initbuf[MAX (256, INT_STRLEN_BOUND (long) + 1)];
struct stat st;
- size_t header_buf_size;
-
- if (filename == NULL)
- f = "";
-
- if (header != NULL)
- free (header);
-
- /* Allow a space on each side of the the filename-or-header. */
- header_buf_size = MAX (chars_per_line, CHARS_FOR_DATE_AND_PAGE + 2) + 1;
- header = (char *) xmalloc (header_buf_size);
-
- if (!standard_header && *custom_header == '\0')
- *header = '\0'; /* blank line header */
+ struct tm *tm;
+
+ /* If parallel files or standard input, use current date. */
+ if (STREQ (filename, "-"))
+ desc = -1;
+ if (desc < 0 || fstat (desc, &st) != 0)
+ st.st_mtime = time (NULL);
+
+ buf = initbuf;
+ tm = localtime (&st.st_mtime);
+ if (! tm)
+ sprintf (buf, "%ld", (long) st.st_mtime);
else
{
- int chars_per_middle, lhs_blanks, rhs_blanks;
- struct tm *tmptr;
- char t_buf[T_BUF_SIZE];
- char *header_text;
-
- /* If parallel files or standard input, use current time. */
- if (desc < 0 || STREQ (filename, "-") || fstat (desc, &st))
- st.st_mtime = time (NULL);
-
- tmptr = localtime (&st.st_mtime);
- strftime (t_buf, T_BUF_SIZE, T_BUF_FMT, tmptr);
-
- chars_per_middle = header_buf_size - 1 - CHARS_FOR_DATE_AND_PAGE;
- if (chars_per_middle < 3)
- {
- header_text = ""; /* Nothing free for a heading */
- lhs_blanks = 1;
- rhs_blanks = 1;
- }
- else
+ size_t bufsize = sizeof initbuf;
+ for (;;)
{
- int chars_free;
- header_text = standard_header ? f : custom_header;
- chars_free = chars_per_middle - (int) strlen (header_text);
- if (chars_free > 1)
- {
- lhs_blanks = chars_free / 2; /* text not truncated */
- rhs_blanks = chars_free - lhs_blanks;
- }
- else
- { /* lhs truncation */
- header_text = header_text - chars_free + 2;
- *header_text = '*';
- lhs_blanks = 1;
- rhs_blanks = 1;
- }
+ *buf = '\1';
+ if (strftime (buf, bufsize, date_format, tm) || ! *buf)
+ break;
+ buf = alloca (bufsize *= 2);
}
-
- sprintf (header, _("%s%*s%s%*sPage"), (test_suite ? NO_DATE : t_buf),
- lhs_blanks, " ", header_text, rhs_blanks, " ");
}
+
+ if (date_text)
+ free (date_text);
+ date_text = xstrdup (buf);
+ file_text = custom_header ? custom_header : desc < 0 ? "" : filename;
+ header_width_available = (chars_per_line
+ - mbswidth (date_text, 0)
+ - mbswidth (file_text, 0));
}
/* Set things up for printing a page
@@ -2404,20 +2365,29 @@ skip_to_page (int page)
static void
print_header (void)
{
+ char page_text[256 + INT_STRLEN_BOUND (int)];
+ int available_width;
+ int lhs_spaces;
+ int rhs_spaces;
+
if (!use_form_feed)
- fprintf (stdout, "\n\n");
+ printf ("\n\n");
output_position = 0;
pad_across_to (chars_per_margin);
print_white_space ();
- if (!standard_header && *custom_header == '\0')
- {
- fprintf (stdout, "%s\n\n\n", header);
- page_number++;
- }
- else
- fprintf (stdout, "%s%5d\n\n\n", header, page_number++);
+ /* The translator must ensure that formatting the translation of
+ "Page %d" does not generate more than (sizeof page_text - 1)
+ bytes. */
+ sprintf (page_text, _("Page %d"), page_number++);
+ available_width = header_width_available - mbswidth (page_text, 0);
+ available_width = MAX (0, available_width);
+ lhs_spaces = available_width >> 1;
+ rhs_spaces = available_width - lhs_spaces;
+
+ printf ("%s%*s%s%*s%s\n\n\n",
+ date_text, lhs_spaces, " ", file_text, rhs_spaces, " ", page_text);
print_a_header = FALSE;
output_position = 0;
@@ -2791,6 +2761,8 @@ Paginate or columnate FILE(s) for printing.\n\
use hat notation (^G) and octal backslash notation\n\
-d, --double-space\n\
double space the output\n\
+ -D, --date-format=FORMAT\n\
+ use FORMAT for the header date\n\
-e[CHAR[WIDTH]], --expand-tabs[=CHAR[WIDTH]]\n\
expand input CHARs (TABs) to tab WIDTH (8)\n\
-F, -f, --form-feed\n\
@@ -2801,7 +2773,6 @@ Paginate or columnate FILE(s) for printing.\n\
printf (_("\
-h HEADER, --header=HEADER\n\
use a centered HEADER instead of filename in page header,\n\
- with long headers left-hand-side truncation may occur,\n\
-h \"\" prints a blank line, don't use -h\"\"\n\
-i[CHAR[WIDTH]], --output-tabs[=CHAR[WIDTH]]\n\
replace spaces with CHARs (TABs) to tab WIDTH (8)\n\