Bug #21128. Reviewed by John Darrington.
authorBen Pfaff <blp@gnu.org>
Sun, 23 Sep 2007 05:59:01 +0000 (05:59 +0000)
committerBen Pfaff <blp@gnu.org>
Sun, 23 Sep 2007 05:59:01 +0000 (05:59 +0000)
* output/paper-size.sh: New test.

* main.c (i18_init): Set up LC_PAPER locale, if available.  Don't
bother with LC_MONETARY locale, since we don't use it anywhere.

* output.c (TWO_CHARS macro): Removed.
(outp_evaluate_dimension): Changed interface, rewritten.  Updated
all callers.
(internal_get_paper_size): Removed.
(parse_unit): New function.
(parse_paper_size): New function.
(outp_get_paper_size): Tweaked interface, rewritten.
(get_standard_paper_size): New function.
(read_paper_conf): New function.
(get_default_paper_size): New function.

* postscript.c (ps_open_driver): Use system default paper size as
default paper, instead of hard-coding US letter.
(handle_option): Allow outp_evaluate_dimension to supply error
message instead of generating it here.

* automake.mk: Add new file.

* paper-size.c: New file.

* command.def: Add DEBUG PAPER SIZE command.

* papersize: Removed.

* automake.mk (dist_pkgsysconf_DATA): Remove papersize.

* acinclude.m4 (PSPP_LC_PAPER): New macro.

* configure.ac: Use PSPP_LC_PAPER.

22 files changed:
ChangeLog
NEWS
acinclude.m4
config/ChangeLog
config/automake.mk
config/papersize [deleted file]
configure.ac
doc/configuring.texi
src/language/ChangeLog
src/language/command.def
src/language/tests/ChangeLog
src/language/tests/automake.mk
src/language/tests/paper-size.c [new file with mode: 0644]
src/output/ChangeLog
src/output/output.c
src/output/output.h
src/output/postscript.c
src/ui/terminal/ChangeLog
src/ui/terminal/main.c
tests/ChangeLog
tests/automake.mk
tests/output/paper-size.sh [new file with mode: 0755]

index b117867f7f790babbb501a46c26894b62a403869..8fd7bc7dc6e705948f76d90a2fe333495029a390 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-09-22  Ben Pfaff  <blp@gnu.org>
+
+       Bug #21128.  Reviewed by John Darrington.
+
+       * acinclude.m4 (PSPP_LC_PAPER): New macro.
+
+       * configure.ac: Use PSPP_LC_PAPER.
+
 2007-08-05  Ben Pfaff  <blp@gnu.org>
 
        Bug #16189.  Reviewed by Jason Stover.
diff --git a/NEWS b/NEWS
index 8e65aa793d99f08fd4a44fe1cf7d47f662cb4862..2ba38211abe5130fb51dfa68a26a3acc22975674 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,5 @@
 PSPP NEWS -- history of user-visible changes.
-Time-stamp: <2007-07-06 23:12:24 blp>
+Time-stamp: <2007-09-22 17:48:06 blp>
 Copyright (C) 1996-9, 2000 Free Software Foundation, Inc.
 See the end for copying conditions.
 
@@ -20,6 +20,12 @@ Changes since 0.4.3:
   may replace any usage of it by SELECT IF following TEMPORARY, which
   has the same effect.
 
+  The default paper size for the PostScript driver is now determined
+  using the PAPERSIZE environment variable, or the LC_PAPER locale
+  category on systems that support it.  If these are not set, the
+  default is now A4, instead of US letter.  To make US letter the
+  default, set PAPERSIZE to "letter" in your environment.
+
   For developers, the build system now requires Autoconf 2.60 and
   Automake 1.10.
 \f
index 4201e22b58c67012d73ece9280e538e35a8b79bb..61290a1802158861f1fbb736838f2c20a6e4690d 100644 (file)
@@ -1,4 +1,4 @@
-dnl Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+dnl Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
@@ -205,4 +205,21 @@ t}
 fi
 AC_SUBST(EXEEXT_FOR_BUILD)])
 
-dnl aclocal.m4 ends here
+dnl Check for LC_PAPER, _NL_PAPER_WIDTH, _NL_PAPER_HEIGHT.
+AC_DEFUN([PSPP_LC_PAPER],
+[AC_CACHE_CHECK(for LC_PAPER, pspp_cv_lc_paper, [
+    pspp_cv_lc_paper=no
+    AC_COMPILE_IFELSE(
+      [AC_LANG_PROGRAM(
+        [#include <locale.h>
+#include <langinfo.h>
+],
+        [(void) LC_PAPER; (void) _NL_PAPER_WIDTH; (void) _NL_PAPER_HEIGHT])],
+      [pspp_cv_lc_paper=yes])
+  ])
+  if test "$pspp_cv_lc_paper" = yes; then
+    AC_DEFINE(HAVE_LC_PAPER, 1, [Define if you have LC_PAPER.])
+  fi
+])
+
+dnl acinclude.m4 ends here
index 93c9e809675aa696b5e1be4c606f82a57cb8957d..27cb2b33268fd8025750993bf763ac2acfd031f1 100644 (file)
@@ -1,3 +1,11 @@
+2007-09-22  Ben Pfaff  <blp@gnu.org>
+
+       Bug #21128.  Reviewed by John Darrington.
+
+       * papersize: Removed.
+
+       * automake.mk (dist_pkgsysconf_DATA): Remove papersize.
+
 2007-08-26  Ben Pfaff  <blp@gnu.org>
 
        * devices: Change raw-ascii from screen to listing device (because
index fa493d525498ab2ef9a9a34f0e92ccf71d4afeb7..ba01a397f3809bde328cc03786a8010cf768b37b 100644 (file)
@@ -2,8 +2,7 @@
 
 
 dist_pkgsysconf_DATA = \
-       config/devices \
-       config/papersize
+       config/devices
 
 psfontsdir = $(pkgsysconfdir)/psfonts
 dist_psfonts_DATA = \
diff --git a/config/papersize b/config/papersize
deleted file mode 100644 (file)
index f3866ed..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-# List of standard paper sizes for use with PSPP output drivers.
-#
-# Valid units include "in"=inches, "cm"=centimeters, "mm"=millimeters.
-# Default units are "in" for dimensions less than 50, "mm" otherwise.
-# This automagically determines units for all the standard sizes.
-#
-# Fractional values are allowed: (1) as decimals, or (2) in the form
-# "a-b/c", which has the value of a, plus b divided by c.
-#
-# Also allowed are synonyms: `"B4/JIS"="B4/ISO"'.  The left hand size
-# is replaced by the right hand size.
-
-# U.S.
-"Letter"               8-1/2 x 11
-"Legal"                        8-1/2 x 14
-"Letter Extra"         9-1/2 x 12
-"Legal Extra"          9-1/2 x 15
-"Executive"            7-1/4 x 10-1/2
-"Ledger"               17 x 11
-"Tabloid"              11 x 17
-"Tabloid Extra"                11.69 x 18
-"US Standard Fanfold"="U.S. Standard Fanfold"
-"U.S. Standard Fanfold"        14-7/8 x 11
-"Standard Fanfold"     8-1/2 x 12
-"Legal Fanfold"                8-1/2 x 12
-
-# Envelopes.
-"DL"                   8-2/3 x 4-1/3
-"Monarch"              3-7/8 x 7-1/2
-"6 3/4 Envelope"="6-3/4 Envelope"
-"6-3/4 Envelope"       3-5/8 x 6-1/2
-"#9"                   3-7/8 x 8-7/8
-"#10"                  4-1/8 x 9-1/2
-"#11"                  4-1/2 x 10-3/8
-"#12"                  4-3/4 x 11
-"#14"                  5 x 11-1/2
-
-# Metric.
-"B4"="B4/ISO"
-"B5"="B5/ISO"
-"A3"           297 x 420
-"A4"           210 x 297
-"B4/ISO"       250 x 353
-"B4/JIS"       257 x 364
-"B5/ISO"       176 x 250
-"B5/JIS"       182 x 257
-"B6"           176 x 125
-"C3"           324 x 458
-"C4"           229 x 324
-"C5"           162 x 229
-"C6"           114 x 162
-"C65"          114 x 229
-"Envelope"     110 x 230
-
-# Demonstration of units.
-#"Bizarre" 55mm x 10in
-
-# Local Variables:
-# fill-prefix: "# "
-# End:
index cb5b4c58f814f4a3d879f7fc142e4e8bb12694ec..ea4cef37de95ff553251123c8245a2b24572d847 100644 (file)
@@ -30,6 +30,7 @@ AC_SYS_LARGEFILE
 AC_FUNC_FSEEKO
 AC_CHECK_LIB(m, sin)
 PSPP_LIBPLOT
+PSPP_LC_PAPER
 AM_CONDITIONAL(WITHCHARTS, test x"$with_libplot" != x"no")
 
 
index c299d9c83795b24a4ec0349906d5510d5e4dcffd..18d24cac45a498518895d17945aacb3702780d2c 100644 (file)
@@ -208,7 +208,6 @@ The following sections further elaborate the contents of the
 * Macro definitions::           Environment variables local to @file{devices}.
 * Device definitions::          Output device descriptions.
 * Dimensions::                  Lengths, widths, sizes, @enddots{}
-* papersize::                   Letter, legal, A4, envelope, @enddots{}
 * Distinguishing line types::   Details on @file{devices} parsing.
 * Tokenizing lines::            Dividing @file{devices} lines into tokens.
 @end menu
@@ -444,36 +443,6 @@ Numbers 50 or greater are assumed to be in millimeters.
 @end itemize
 @end itemize
 
-@node papersize
-@subsection Paper sizes
-
-Output drivers usually deal with some sort of hardcopy media.  This
-media is called @dfn{paper} by the drivers, though in reality it could
-be a transparency or film or thinly veiled sarcasm.  To make it easier
-for you to deal with paper, PSPP allows you to have (of course!) a
-configuration file that gives symbolic names, like ``letter'' or
-``legal'' or ``a4'', to paper sizes, rather than forcing you to use
-cryptic numbers like ``8-1/2 x 11'' or ``210 by 297''.  Surprisingly
-enough, this configuration file is named @file{papersize}.
-@xref{Configuration files}.
-
-When PSPP tries to connect a symbolic paper name to a paper size, it
-reads and parses each non-comment line in the file, in order.  The first
-field on each line must be a symbolic paper name in double quotes.
-Paper names may not contain double quotes.  Paper names are not
-case-sensitive: @samp{legal} and @samp{Legal} are equivalent.
-
-If a match is found for the paper name, the rest of the line is parsed.
-If it is found to be a pair of dimensions (@pxref{Dimensions}) separated
-by either @samp{x} or @samp{by}, then those are taken to be the paper
-size, in order of width followed by length.  There @emph{must} be at
-least one space on each side of @samp{x} or @samp{by}.
-
-Otherwise the line must be of the form
-@samp{"@var{paper-1}"="@var{paper-2}"}.  In this case the target of the
-search becomes paper name @var{paper-2} and the search through the file
-continues.
-
 @node Distinguishing line types
 @subsection How lines are divided into types
 
@@ -594,9 +563,16 @@ title and subtitle are printed at the top of each page.  Default:
 
 @item paper-size=@var{paper-size}
 
-Paper size, either as a symbolic name (i.e., @code{letter} or @code{a4})
-or specific measurements (i.e., @code{8-1/2x11} or @code{"210 x 297"}.
-@xref{papersize, , Paper sizes}.  Default: @code{letter}.
+Paper size.  You may specify a name (e.g.@: @code{a4}, @code{letter})
+or measurements (e.g.@: @code{210x297}, @code{8.5x11in}).
+
+The default paper size is taken from the @env{PAPERSIZE} environment
+variable or the file indicated by the @env{PAPERCONF} environment
+variable, if either variable is set.  If not, and your system supports
+the @code{LC_PAPER} locale category, then the default paper size is
+taken from the locale.  Otherwise, if @file{/etc/papersize} exists,
+the default paper size is read from it.  As a last resort, A4 paper is
+assumed.
 
 @item orientation=@var{orientation}
 
@@ -898,15 +874,10 @@ support was compiled into PSPP.
 The basename used to search for the driver definition file.
 @xref{Output devices}.  @xref{File locations}.  Default: @code{devices}.
 
-@item STAT_OUTPUT_PAPERSIZE_FILE
-
-The basename used to search for the papersize file.  @xref{papersize}.
-@xref{File locations}.  Default: @code{papersize}.
-
 @item STAT_OUTPUT_INIT_PATH
 
-The path used to search for the driver definition file and the papersize
-file.  @xref{File locations}.  Default: the standard configuration path.
+The path used to search for the driver definition file.
+@xref{File locations}.  Default: the standard configuration path.
 
 @item TMPDIR
 
index d25c2d0379b7210e1d71fcff6453ff465894161f..840278b2b04654734f816b527bc84b5d68e4a76e 100644 (file)
@@ -1,10 +1,15 @@
+2007-09-22  Ben Pfaff  <blp@gnu.org>
+
+       Bug #21128.  Reviewed by John Darrington.
+
+       * command.def: Add DEBUG PAPER SIZE command.
+
 2007-09-05  John Darrington <john@darrington.wattle.id.au>
 
        * command.c (do_parse_command): Translate CMD_FAILURE into
        CMD_CASCADING_FAILURE, if the ERRMODE_STOP is set on the syntax
        source. 
        
-       
 2007-06-06  Ben Pfaff  <blp@gnu.org>
 
        * command.def: Add DEBUG DATASHEET command.  Remove DEBUG CASEFILE
index 7a89ae0a1631cab8384a82c7911b772ea6b74143..f77bd6920acd7d9a717b2596f2472344a14ce09e 100644 (file)
@@ -131,6 +131,7 @@ DEF_CMD (S_INPUT_PROGRAM, 0, "REREAD", cmd_reread)
 DEF_CMD (S_ANY, F_TESTING, "DEBUG DATASHEET", cmd_debug_datasheet)
 DEF_CMD (S_ANY, F_TESTING, "DEBUG EVALUATE", cmd_debug_evaluate)
 DEF_CMD (S_ANY, F_TESTING, "DEBUG MOMENTS", cmd_debug_moments)
+DEF_CMD (S_ANY, F_TESTING, "DEBUG PAPER SIZE", cmd_debug_paper_size)
 DEF_CMD (S_ANY, F_TESTING, "DEBUG POOL", cmd_debug_pool)
 DEF_CMD (S_ANY, F_TESTING, "DEBUG FLOAT FORMAT", cmd_debug_float_format)
 DEF_CMD (S_ANY, F_TESTING, "DEBUG XFORM FAIL", cmd_debug_xform_fail)
index 295c5418392699daf026e5ebb60f0fd26e263570..565064522ff9e7967451a3ccf913e65543378f7f 100644 (file)
@@ -1,3 +1,11 @@
+2007-09-22  Ben Pfaff  <blp@gnu.org>
+
+       Bug #21128.  Reviewed by John Darrington.
+
+       * automake.mk: Add new file.
+
+       * paper-size.c: New file.
+
 2007-06-06  Ben Pfaff  <blp@gnu.org>
 
        * automake.mk: Add new file.
index bbcd777b3ebeec54c6b0cece014015a6100b3388..49c71da1bc89f1fa5b9babed06e50448421209dd 100644 (file)
@@ -8,6 +8,7 @@ language_tests_sources = \
        src/language/tests/datasheet-test.c \
        src/language/tests/float-format.c \
        src/language/tests/moments-test.c \
+       src/language/tests/paper-size.c \
        src/language/tests/pool-test.c \
        $(language_tests_built_sources)
 
diff --git a/src/language/tests/paper-size.c b/src/language/tests/paper-size.c
new file mode 100644 (file)
index 0000000..d8c49a5
--- /dev/null
@@ -0,0 +1,45 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2007 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <language/command.h>
+#include <language/lexer/lexer.h>
+#include <libpspp/assertion.h>
+#include <output/output.h>
+
+/* Executes the DEBUG PAPER SIZE command. */
+int
+cmd_debug_paper_size (struct lexer *lexer, struct dataset *ds UNUSED)
+{
+  int h, v;
+
+  if (!lex_force_string (lexer))
+    return CMD_FAILURE;
+
+  printf ("\"%s\" => ", ds_cstr (lex_tokstr (lexer)));
+  if (outp_get_paper_size (ds_cstr (lex_tokstr (lexer)), &h, &v))
+    printf ("%.1f x %.1f in, %.0f x %.0f mm\n",
+            h / 72000., v / 72000.,
+            h / (72000 / 25.4), v / (72000 / 25.4));
+  else
+    printf ("error\n");
+  lex_get (lexer);
+
+  return lex_end_of_command (lexer);
+}
index f7ce7b5c841eb622ee3ebe8b33fd9d5e9c2f21cb..adabbcde32e077796e704b26296eb68ac8332ff1 100644 (file)
@@ -1,3 +1,23 @@
+2007-09-22  Ben Pfaff  <blp@gnu.org>
+
+       Bug #21128.  Reviewed by John Darrington.
+
+       * output.c (TWO_CHARS macro): Removed.
+       (outp_evaluate_dimension): Changed interface, rewritten.  Updated
+       all callers.
+       (internal_get_paper_size): Removed.
+       (parse_unit): New function.
+       (parse_paper_size): New function.
+       (outp_get_paper_size): Tweaked interface, rewritten.
+       (get_standard_paper_size): New function.
+       (read_paper_conf): New function.
+       (get_default_paper_size): New function.
+
+       * postscript.c (ps_open_driver): Use system default paper size as
+       default paper, instead of hard-coding US letter.
+       (handle_option): Allow outp_evaluate_dimension to supply error
+       message instead of generating it here.
+
 2007-09-21  Ben Pfaff  <blp@gnu.org>
 
        * ascii.c (struct ascii_driver_ext): New member reported_error.
index 5a24d89547a8ea054eb5dd3b5721a7dca761fe0b..842e1c15c63bc383219c4a5de027883b2c086aff 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include "output.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
+
 #include <ctype.h>
-#include <libpspp/alloc.h>
+#include <errno.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+
 #include <data/file-name.h>
-#include "htmlP.h"
-#include "intprops.h"
-#include <libpspp/misc.h>
 #include <data/settings.h>
+#include <libpspp/alloc.h>
+#include <libpspp/misc.h>
 #include <libpspp/str.h>
+#include <output/htmlP.h>
+#include <output/output.h>
+
 #include "error.h"
+#include "intprops.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -803,275 +808,274 @@ outp_match_keyword (const char *s, const struct outp_option *tab, int *subcat)
   return -1;
 }
 
-/* Encapsulate two characters in a single int. */
-#define TWO_CHARS(A, B)                                \
-       ((A) + ((B)<<8))
-
-/* Determines the size of a dimensional measurement and returns the
-   size in units of 1/72000".  Units if not specified explicitly are
-   inches for values under 50, millimeters otherwise.  Returns 0,
-   stores NULL to *TAIL on error; otherwise returns dimension, stores
-   address of next */
-int
-outp_evaluate_dimension (char *dimen, char **tail)
+/* Parses UNIT as a dimensional unit.  Returns the multiplicative
+   factor needed to change a quantity measured in that unit into
+   1/72000" units.  If UNIT is empty, it is treated as
+   millimeters.  If the unit is unrecognized, returns 0. */
+static double
+parse_unit (const char *unit)
 {
-  char *s = dimen;
-  char *ptail;
-  double value;
-
-  value = strtod (s, &ptail);
-  if (ptail == s)
-    goto lossage;
-  if (*ptail == '-')
-    {
-      double b, c;
-      s = &ptail[1];
-      b = strtod (s, &ptail);
-      if (b <= 0.0 || ptail == s)
-       goto lossage;
-      if (*ptail != '/')
-       goto lossage;
-      s = &ptail[1];
-      c = strtod (s, &ptail);
-      if (c <= 0.0 || ptail == s)
-       goto lossage;
-      s = ptail;
-      if (c == 0.0)
-       goto lossage;
-      if (value > 0)
-       value += b / c;
-      else
-       value -= b / c;
-    }
-  else if (*ptail == '/')
-    {
-      double b;
-      s = &ptail[1];
-      b = strtod (s, &ptail);
-      if (b <= 0.0 || ptail == s)
-       goto lossage;
-      s = ptail;
-      value /= b;
-    }
-  else
-    s = ptail;
-  if (*s == 0 || isspace ((unsigned char) *s))
-    {
-      if (value < 50.0)
-       value *= 72000;
-      else
-       value *= 72000 / 25.4;
-    }
-  else
+  struct unit
     {
+      char name[3];
       double factor;
+    };
 
-      /* Standard TeX units are supported. */
-      if (*s == '"')
-       factor = 72000, s++;
-      else
-       switch (TWO_CHARS (s[0], s[1]))
-         {
-         case TWO_CHARS ('p', 't'):
-           factor = 72000 / 72.27;
-           break;
-         case TWO_CHARS ('p', 'c'):
-           factor = 72000 / 72.27 * 12.0;
-           break;
-         case TWO_CHARS ('i', 'n'):
-           factor = 72000;
-           break;
-         case TWO_CHARS ('b', 'p'):
-           factor = 72000 / 72.0;
-           break;
-         case TWO_CHARS ('c', 'm'):
-           factor = 72000 / 2.54;
-           break;
-         case TWO_CHARS ('m', 'm'):
-           factor = 72000 / 25.4;
-           break;
-         case TWO_CHARS ('d', 'd'):
-           factor = 72000 / 72.27 * 1.0700086;
-           break;
-         case TWO_CHARS ('c', 'c'):
-           factor = 72000 / 72.27 * 12.840104;
-           break;
-         case TWO_CHARS ('s', 'p'):
-           factor = 72000 / 72.27 / 65536.0;
-           break;
-         default:
-           error (0, 0,
-                   _("unit \"%s\" is unknown in dimension \"%s\""), s, dimen);
-           *tail = NULL;
-           return 0;
-         }
-      ptail += 2;
-      value *= factor;
-    }
-  if (value <= 0.0)
-    goto lossage;
-  if (tail)
-    *tail = ptail;
-  return value + 0.5;
-
-lossage:
-  *tail = NULL;
-  error (0, 0, _("bad dimension \"%s\""), dimen);
+  static const struct unit units[] =
+    {
+      {"pt", 72000 / 72},
+      {"pc", 72000 / 72 * 12.0},
+      {"in", 72000},
+      {"cm", 72000 / 2.54},
+      {"mm", 72000 / 25.4},
+      {"", 72000 / 25.4},
+    };
+
+  const struct unit *p;
+
+  unit += strspn (unit, CC_SPACES);
+  for (p = units; p < units + sizeof units / sizeof *units; p++)
+    if (!strcasecmp (unit, p->name))
+      return p->factor;
+  return 0.0;
+}
+
+/* Determines the size of a dimensional measurement and returns
+   the size in units of 1/72000".  Units are assumed to be
+   millimeters unless otherwise specified.  Returns 0 on
+   error. */
+int
+outp_evaluate_dimension (const char *dimen)
+{
+  double raw, factor;
+  char *tail;
+
+  /* Number. */
+  raw = strtod (dimen, &tail);
+  if (raw <= 0.0)
+    goto syntax_error;
+
+  /* Unit. */
+  factor = parse_unit (tail);
+  if (factor == 0.0)
+    goto syntax_error;
+
+  return raw * factor;
+
+syntax_error:
+  error (0, 0, _("`%s' is not a valid length."), dimen);
   return 0;
 }
 
 /* Stores the dimensions in 1/72000" units of paper identified by
-   SIZE, which is of form `HORZ x VERT' or `HORZ by VERT' where each
-   of HORZ and VERT are dimensions, into *H and *V.  Return true on
-   success. */
+   SIZE, which is of form `HORZ x VERT [UNIT]' where HORZ and
+   VERT are numbers and UNIT is an optional unit of measurement,
+   into *H and *V.  Return true on success. */
 static bool
-internal_get_paper_size (char *size, int *h, int *v)
+parse_paper_size (const char *size, int *h, int *v)
 {
+  double raw_h, raw_v, factor;
   char *tail;
 
-  while (isspace ((unsigned char) *size))
-    size++;
-  *h = outp_evaluate_dimension (size, &tail);
-  if (tail == NULL)
+  /* Width. */
+  raw_h = strtod (size, &tail);
+  if (raw_h <= 0.0)
+    return false;
+
+  /* Delimiter. */
+  tail += strspn (tail, CC_SPACES "x,");
+
+  /* Length. */
+  raw_v = strtod (tail, &tail);
+  if (raw_v <= 0.0)
+    return false;
+
+  /* Unit. */
+  factor = parse_unit (tail);
+  if (factor == 0.0)
     return false;
-  while (isspace ((unsigned char) *tail))
-    tail++;
-  if (*tail == 'x')
-    tail++;
-  else if (*tail == 'b' && tail[1] == 'y')
-    tail += 2;
-  else
-    {
-      error (0, 0, _("`x' expected in paper size `%s'"), size);
-      return false;
-    }
-  *v = outp_evaluate_dimension (tail, &tail);
-  if (tail == NULL)
-    return 0;
-  while (isspace ((unsigned char) *tail))
-    tail++;
-  if (*tail)
-    {
-      error (0, 0, _("trailing garbage `%s' on paper size `%s'"), tail, size);
-      return false;
-    }
 
+  *h = raw_h * factor + .5;
+  *v = raw_v * factor + .5;
   return true;
 }
 
-/* Stores the dimensions, in 1/72000" units, of paper identified by
-   SIZE into *H and *V.  SIZE may be a pair of dimensions of form `H x
-   V', or it may be a case-insensitive paper identifier, which is
-   looked up in the `papersize' configuration file.  Returns true
-   on success.  May modify SIZE. */
-/* Don't read further unless you've got a strong stomach. */
-bool
-outp_get_paper_size (char *size, int *h, int *v)
+static bool
+get_standard_paper_size (struct substring name, int *h, int *v)
 {
-  struct paper_size
+  static const char *sizes[][2] =
     {
-      char *name;
-      int use;
-      int h, v;
+      {"a0", "841 x 1189 mm"},
+      {"a1", "594 x 841 mm"},
+      {"a2", "420 x 594 mm"},
+      {"a3", "297 x 420 mm"},
+      {"a4", "210 x 297 mm"},
+      {"a5", "148 x 210 mm"},
+      {"b5", "176 x 250 mm"},
+      {"a6", "105 x 148 mm"},
+      {"a7", "74 x 105 mm"},
+      {"a8", "52 x 74 mm"},
+      {"a9", "37 x 52 mm"},
+      {"a10", "26 x 37 mm"},
+      {"b0", "1000 x 1414 mm"},
+      {"b1", "707 x 1000 mm"},
+      {"b2", "500 x 707 mm"},
+      {"b3", "353 x 500 mm"},
+      {"b4", "250 x 353 mm"},
+      {"letter", "612 x 792 pt"},
+      {"legal", "612 x 1008 pt"},
+      {"executive", "522 x 756 pt"},
+      {"note", "612 x 792 pt"},
+      {"11x17", "792 x 1224 pt"},
+      {"tabloid", "792 x 1224 pt"},
+      {"statement", "396 x 612 pt"},
+      {"halfletter", "396 x 612 pt"},
+      {"halfexecutive", "378 x 522 pt"},
+      {"folio", "612 x 936 pt"},
+      {"quarto", "610 x 780 pt"},
+      {"ledger", "1224 x 792 pt"},
+      {"archA", "648 x 864 pt"},
+      {"archB", "864 x 1296 pt"},
+      {"archC", "1296 x 1728 pt"},
+      {"archD", "1728 x 2592 pt"},
+      {"archE", "2592 x 3456 pt"},
+      {"flsa", "612 x 936 pt"},
+      {"flse", "612 x 936 pt"},
+      {"csheet", "1224 x 1584 pt"},
+      {"dsheet", "1584 x 2448 pt"},
+      {"esheet", "2448 x 3168 pt"},
     };
 
-  FILE *f;
-  char *pprsz_fn;
-
-  struct string line;
-  int line_number = 0;
-
-  bool free_it = false;
-  bool result = false;
-  char *ep;
-
-  while (isspace ((unsigned char) *size))
-    size++;
-  if (isdigit ((unsigned char) *size))
-    return internal_get_paper_size (size, h, v);
-  ep = size;
-  while (*ep)
-    ep++;
-  while (isspace ((unsigned char) *ep) && ep >= size)
-    ep--;
-  if (ep == size)
-    {
-      error (0, 0, _("paper size name cannot be empty"));
-      return 0;
-    }
-
-  ep++;
-  if (*ep)
-    *ep = 0;
-
-  pprsz_fn = fn_search_path (fn_getenv_default ("STAT_OUTPUT_PAPERSIZE_FILE",
-                                               "papersize"),
-                            fn_getenv_default ("STAT_OUTPUT_INIT_PATH",
-                                               config_path));
+  size_t i;
 
-  ds_init_empty (&line);
+  for (i = 0; i < sizeof sizes / sizeof *sizes; i++)
+    if (ss_equals_case (ss_cstr (sizes[i][0]), name))
+      {
+        bool ok = parse_paper_size (sizes[i][1], h, v);
+        assert (ok);
+        return ok;
+      }
+  error (0, 0, _("unknown paper type `%.*s'"),
+         (int) ss_length (name), ss_data (name));
+  return false;
+}
 
-  if (pprsz_fn == NULL)
-    {
-      error (0, 0, _("cannot find `papersize' configuration file"));
-      goto exit;
-    }
+/* Reads file FILE_NAME to find a paper size.  Stores the
+   dimensions, in 1/72000" units, into *H and *V.  Returns true
+   on success, false on failure. */
+static bool
+read_paper_conf (const char *file_name, int *h, int *v)
+{
+  struct string line = DS_EMPTY_INITIALIZER;
+  int line_number = 0;
+  FILE *file;
 
-  f = fopen (pprsz_fn, "r");
-  if (!f)
+  file = fopen (file_name, "r");
+  if (file == NULL)
     {
-      error (0, errno, _("error opening \"%s\""), pprsz_fn);
-      goto exit;
+      error (0, errno, _("error opening \"%s\""), file_name);
+      return false;
     }
 
   for (;;)
     {
-      struct substring p, name;
+      struct substring name;
 
-      if (!ds_read_config_line (&line, &line_number, f))
+      if (!ds_read_config_line (&line, &line_number, file))
        {
-         if (ferror (f))
-           error (0, errno, _("error reading \"%s\""), pprsz_fn);
+         if (ferror (file))
+           error (0, errno, _("error reading \"%s\""), file_name);
          break;
        }
 
-      p = ds_ss (&line);
-      ss_ltrim (&p, ss_cstr (CC_SPACES));
-      if (!ss_match_char (&p, '"') || !ss_get_until (&p, '"', &name))
-       goto lex_error;
-      if (ss_compare (name, ss_cstr (size)))
-       continue;
+      name = ds_ss (&line);
+      ss_trim (&name, ss_cstr (CC_SPACES));
+      if (!ss_is_empty (name))
+        {
+          bool ok = get_standard_paper_size (name, h, v);
+          fclose (file);
+          ds_destroy (&line);
+          return ok;
+        }
+    }
 
-      ss_ltrim (&p, ss_cstr (CC_SPACES));
-      if (ss_match_char (&p, '='))
-       {
-          if (free_it)
-            free (size);
-          ss_trim (&p, ss_cstr (CC_SPACES));
-          size = ss_xstrdup (p);
-         free_it = true;
-         continue;
-       }
-      size = ss_data (p);
-      break;
+  fclose (file);
+  ds_destroy (&line);
+  error (0, 0, _("paper size file \"%s\" does not state a paper size"),
+         file_name);
+  return false;
+}
 
-    lex_error:
-      error_at_line (0, 0, pprsz_fn, line_number,
-                     _("syntax error in paper size definition"));
-    }
+/* The user didn't specify a paper size, so let's choose a
+   default based on his environment.  Stores the
+   dimensions, in 1/72000" units, into *H and *V.  Returns true
+   on success, false on failure. */
+static bool
+get_default_paper_size (int *h, int *v)
+{
+  /* libpaper in Debian (and other distributions?) allows the
+     paper size to be specified in $PAPERSIZE or in a file
+     specified in $PAPERCONF. */
+  if (getenv ("PAPERSIZE") != NULL)
+    return get_standard_paper_size (ss_cstr (getenv ("PAPERSIZE")), h, v);
+  if (getenv ("PAPERCONF") != NULL)
+    return read_paper_conf (getenv ("PAPERCONF"), h, v);
+
+#if HAVE_LC_PAPER
+  /* LC_PAPER is a non-standard glibc extension. */
+  *h = (int) nl_langinfo(_NL_PAPER_WIDTH) * (72000 / 25.4);
+  *v = (int) nl_langinfo(_NL_PAPER_HEIGHT) * (72000 / 25.4);
+  if (*h > 0 && *v > 0)
+     return true;
+#endif
+
+  /* libpaper defaults to /etc/papersize. */
+  if (fn_exists ("/etc/papersize"))
+    return read_paper_conf ("/etc/papersize", h, v);
+
+  /* Can't find a default. */
+  return false;
+}
 
-  /* We found the one we want! */
-  result = internal_get_paper_size (size, h, v);
+/* Stores the dimensions, in 1/72000" units, of paper identified
+   by SIZE into *H and *V.  SIZE can be the name of a kind of
+   paper ("a4", "letter", ...) or a pair of dimensions
+   ("210x297", "8.5x11in", ...).  Returns true on success, false
+   on failure.  On failure, *H and *V are set for A4 paper. */
+bool
+outp_get_paper_size (const char *size, int *h, int *v)
+{
+  struct substring s;
+  bool ok;
 
-exit:
-  ds_destroy (&line);
-  if (free_it)
-    free (size);
+  s = ss_cstr (size);
+  ss_trim (&s, ss_cstr (CC_SPACES));
 
-  if (!result)
-    error (0, 0, _("error reading paper size definition file"));
+  if (ss_is_empty (s))
+    {
+      /* Treat empty string as default paper size. */
+      ok = get_default_paper_size (h, v);
+    }
+  else if (isdigit (ss_first (s)))
+    {
+      /* Treat string that starts with digit as explicit size. */
+      ok = parse_paper_size (size, h, v);
+      if (!ok)
+        error (0, 0, _("syntax error in paper size `%s'"), size);
+    }
+  else
+    {
+      /* Check against standard paper sizes. */
+      ok = get_standard_paper_size (s, h, v);
+    }
 
-  return result;
+  /* Default to A4 on error. */
+  if (!ok)
+    {
+      *h = 210 * (72000 / 25.4);
+      *v = 297 * (72000 / 25.4);
+    }
+  return ok;
 }
 
 /* If D is NULL, returns the first enabled driver if any, NULL if
index 2338a0d87bf64e761023a49772f99a3d89ac7fd9..2585aa8cbf346783d02557d596db5757e8d4339a 100644 (file)
@@ -152,8 +152,8 @@ bool outp_parse_options (struct substring options,
                          struct outp_driver *);
 int outp_match_keyword (const char *, const struct outp_option *, int *);
 
-int outp_evaluate_dimension (char *, char **);
-bool outp_get_paper_size (char *, int *h, int *v);
+int outp_evaluate_dimension (const char *);
+bool outp_get_paper_size (const char *, int *h, int *v);
 
 void outp_open_page (struct outp_driver *);
 void outp_close_page (struct outp_driver *);
index 27d0404f8166fb8996677882a9743e6b7e0d86de..9a33807096bcd092c03380683384443f005ad133 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007 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
@@ -138,8 +138,7 @@ ps_open_driver (struct outp_driver *this, struct substring options)
   x->draw_headers = true;
   x->page_number = 0;
   x->portrait = true;
-  x->paper_width = PSUS * 17 / 2;
-  x->paper_length = PSUS * 11;
+  outp_get_paper_size ("", &x->paper_width, &x->paper_length);
   x->left_margin = PSUS / 2;
   x->right_margin = PSUS / 2;
   x->top_margin = PSUS / 2;
@@ -380,14 +379,10 @@ handle_option (struct outp_driver *this, const char *key,
       break;
     case dimension_arg:
       {
-       int dimension = outp_evaluate_dimension (value, NULL);
+       int dimension = outp_evaluate_dimension (value);
 
        if (dimension <= 0)
-         {
-           error (0, 0, _("value for `%s' must be a dimension of positive "
-                           "length (i.e., `1in')"), key);
-           break;
-         }
+          break;
        switch (subcat)
          {
          case 0:
index 374bc52bf5cd59945539d5e6cfaa9dbe807f9491..0e6e014d9b49b9c6f5c186ec442a67813e0a9d78 100644 (file)
@@ -1,3 +1,10 @@
+2007-09-22  Ben Pfaff  <blp@gnu.org>
+
+       Bug #21128.  Reviewed by John Darrington.
+
+       * main.c (i18_init): Set up LC_PAPER locale, if available.  Don't
+       bother with LC_MONETARY locale, since we don't use it anywhere.
+
 2007-08-26  Ben Pfaff  <blp@gnu.org>
 
        Bug #17238.  Thanks to John Darrington for review.
index 66fedf04fd900d9c97427f023b7583ab334b1035..46ded354f7e392903c61d93712d0ad8baff38610 100644 (file)
@@ -150,7 +150,9 @@ i18n_init (void)
 #if HAVE_LC_MESSAGES
   setlocale (LC_MESSAGES, "");
 #endif
-  setlocale (LC_MONETARY, "");
+#if HAVE_LC_PAPER
+  setlocale (LC_PAPER, "");
+#endif
   bindtextdomain (PACKAGE, locale_dir);
   textdomain (PACKAGE);
 #endif /* ENABLE_NLS */
index d5f95608c5dd861bc45b9a3163ba35d08e5e3324..e91645ce4c14434d050932a4eb6023362d9603c4 100644 (file)
@@ -1,3 +1,9 @@
+2007-09-22  Ben Pfaff  <blp@gnu.org>
+
+       Bug #21128.  Reviewed by John Darrington.
+
+       * output/paper-size.sh: New test.
+
 2007-09-21  Ben Pfaff  <blp@gnu.org>
 
        * bugs/unwritable-dir.sh: New test for bug #21117.
index 1b7a38ac8fbed0cd0ff5d8fae26878f75cdb19b7..3ee837dab621d7bbaceb50db9267c657a146f0e6 100644 (file)
@@ -121,6 +121,7 @@ dist_TESTS = \
        tests/bugs/temp-freq.sh \
        tests/bugs/print-crash.sh \
        tests/bugs/keep-all.sh \
+       tests/output/paper-size.sh \
        tests/xforms/recode.sh \
        tests/stats/descript-basic.sh \
        tests/stats/descript-missing.sh \
diff --git a/tests/output/paper-size.sh b/tests/output/paper-size.sh
new file mode 100755 (executable)
index 0000000..5473937
--- /dev/null
@@ -0,0 +1,96 @@
+#!/bin/sh
+
+# This program tests paper size support.
+
+TEMPDIR=/tmp/pspp-tst-$$
+
+# ensure that top_builddir  are absolute
+if [ -z "$top_builddir" ] ; then top_builddir=. ; fi
+if [ -z "$top_srcdir" ] ; then top_srcdir=. ; fi
+top_builddir=`cd $top_builddir; pwd`
+PSPP=$top_builddir/src/ui/terminal/pspp
+
+# ensure that top_srcdir is absolute
+top_srcdir=`cd $top_srcdir; pwd`
+
+STAT_CONFIG_PATH=$top_srcdir/config
+export STAT_CONFIG_PATH
+
+LANG=C
+export LANG
+
+cleanup()
+{
+     cd /
+     rm -rf $TEMPDIR
+}
+
+
+fail()
+{
+    echo $activity
+    echo FAILED
+    cleanup;
+    exit 1;
+}
+
+
+no_result()
+{
+    echo $activity
+    echo NO RESULT;
+    cleanup;
+    exit 2;
+}
+
+pass()
+{
+    cleanup;
+    exit 0;
+}
+
+mkdir -p $TEMPDIR
+
+cd $TEMPDIR
+
+activity="Create File 1"
+cat > paper-size.pspp <<EOF
+debug paper size ''.
+debug paper size 'a4'.
+debug paper size 'letter'.
+debug paper size '10x14in'.
+debug paper size '210x297mm'.
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="Run pspp 1"
+PAPERSIZE=letter $SUPERVISOR $PSPP --testing-mode paper-size.pspp > paper-size.out
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="compare results"
+diff -b  $TEMPDIR/paper-size.out - <<EOF
+"" => 8.5 x 11.0 in, 216 x 279 mm
+"a4" => 8.3 x 11.7 in, 210 x 297 mm
+"letter" => 8.5 x 11.0 in, 216 x 279 mm
+"10x14in" => 10.0 x 14.0 in, 254 x 356 mm
+"210x297mm" => 8.3 x 11.7 in, 210 x 297 mm
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+activity="Create File 2"
+cat > paper-size-2.pspp <<EOF
+debug paper size ''.
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="Run pspp 2"
+PAPERSIZE=a4 $SUPERVISOR $PSPP --testing-mode paper-size-2.pspp > paper-size-2.out
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="compare results 2"
+diff -b  $TEMPDIR/paper-size-2.out - <<EOF
+"" => 8.3 x 11.7 in, 210 x 297 mm
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+pass;