Patch #6210: implement ability to resize output device parameters to
authorBen Pfaff <blp@gnu.org>
Wed, 26 Sep 2007 04:24:07 +0000 (04:24 +0000)
committerBen Pfaff <blp@gnu.org>
Wed, 26 Sep 2007 04:24:07 +0000 (04:24 +0000)
fit terminal window size as it changes.  Reviewed by John Darrington.

* automake.mk (src_ui_terminal_libui_a_SOURCES): Add new files.

* terminal.c: New file.

* terminal.h: New file.

* main.c (main): No need to set up SIGWINCH handler any longer.
But we do need to call terminal_init.
(set_fallback_viewport): Move to terminal.c.
[HAVE_LIBNCURSES] (get_termcap_viewport): Ditto.
[!HAVE_LIBNCURSES] (get_termcap_viewport): Ditto.

* read-line.c (readln_read): After the first line of a command,
call terminal_check_size to allow it to re-detect the terminal
size.

* ascii.c: Implement ability to resize output device parameters to
fit terminal window size as it changes.
(struct ascii_driver_ext): New members `auto_width',
`auto_length'.
(ascii_open_driver): Initialize new members, call
update_page_size.
(update_page_size): New function to update device size.
(handle_option): Support new "auto" setting for length, width.
(ascii_open_page): Call update_page_size.

* devices (tty-ascii): Set length and width to "auto", so that
they reflect the current size of the terminal window as it
changes.

config/ChangeLog
config/devices
doc/configuring.texi
src/output/ChangeLog
src/output/ascii.c
src/ui/terminal/ChangeLog
src/ui/terminal/automake.mk
src/ui/terminal/main.c
src/ui/terminal/read-line.c
src/ui/terminal/terminal.c [new file with mode: 0644]
src/ui/terminal/terminal.h [new file with mode: 0644]

index 27cb2b33268fd8025750993bf763ac2acfd031f1..dbf6c3ad65409bada9b25932265d4a4f719bae84 100644 (file)
@@ -1,3 +1,9 @@
+2007-09-25  Ben Pfaff  <blp@gnu.org>
+
+       * devices (tty-ascii): Set length and width to "auto", so that
+       they reflect the current size of the terminal window as it
+       changes.
+
 2007-09-22  Ben Pfaff  <blp@gnu.org>
 
        Bug #21128.  Reviewed by John Darrington.
index 7da8eac81a79e6bf6921d3eabf5653535b9803b3..48513fe6bc83899b127136dad62994f2a28cc72c 100644 (file)
@@ -50,8 +50,7 @@ define list-output-file "pspp.list"
 
 # Generic ASCII devices
 tty-ascii:ascii:screen:squeeze=on headers=off top-margin=0 bottom-margin=0 \
-  paginate=off length=${viewlength} width=${viewwidth} \
-  output-file=${tty-output-file}
+  paginate=off length=auto width=auto output-file=${tty-output-file}
 list-ascii:ascii:listing:length=66 width=79 output-file=${list-output-file}
 raw-ascii:ascii:listing:width=9999 length=9999 output-file=${list-output-file} \
   emphasis=none headers=off paginate=off squeeze=on \
index 18d24cac45a498518895d17945aacb3702780d2c..164d9ab1aac182a38c04120ef1028e8fb30684aa 100644 (file)
@@ -681,13 +681,17 @@ requested.  Default: @code{on}.
 
 @item length=@var{line-count}
 
-Physical length of a page, in lines.  Headers and margins are subtracted
-from this value.  Default: @code{66}.
+Physical length of a page.  Headers and margins are subtracted from
+this value.  You may specify the number of lines as a number, or for
+screen output you may specify @code{auto} to track the height of the
+terminal as it changes.  Default: @code{66}.
 
 @item width=@var{character-count}
 
-Physical width of a page, in characters.  Margins are subtracted from
-this value.  Default: @code{130}.
+Physical width of a page.  Margins are subtracted from this value.
+You may specify the width as a number of characters, or for screen
+output you may specify @code{auto} to track the width of the terminal
+as it changes.  Default: @code{79}.
 
 @item top-margin=@var{top-margin-lines}
 
index adabbcde32e077796e704b26296eb68ac8332ff1..0073124e73f57f873e9d3609a172449902bfbb3a 100644 (file)
@@ -1,3 +1,17 @@
+2007-09-25  Ben Pfaff  <blp@gnu.org>
+
+       Patch #6210.  Reviewed by John Darrington.
+
+       * ascii.c: Implement ability to resize output device parameters to
+       fit terminal window size as it changes.
+       (struct ascii_driver_ext): New members `auto_width',
+       `auto_length'.
+       (ascii_open_driver): Initialize new members, call
+       update_page_size.
+       (update_page_size): New function to update device size.
+       (handle_option): Support new "auto" setting for length, width.
+       (ascii_open_page): Call update_page_size.
+
 2007-09-22  Ben Pfaff  <blp@gnu.org>
 
        Bug #21128.  Reviewed by John Darrington.
index bdb02dbf3c8443a4c86eff9ca13ec2d50b837ff0..f2dff490b8bb23bb92741ad68b280ed740458217 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 
 #include <data/file-name.h>
+#include <data/settings.h>
 #include <libpspp/alloc.h>
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
@@ -50,8 +51,8 @@
 
    headers=on|off               Put headers at top of page?
    emphasis=bold|underline|none Style to use for emphasis.
-   length=66
-   width=130
+   length=66|auto
+   width=79|auto
    squeeze=off|on               Squeeze multiple newlines into exactly one.
 
    top-margin=2
@@ -110,6 +111,8 @@ struct ascii_driver_ext
     const char *chart_type;     /* Type of charts to output; NULL for none. */
     const char *chart_file_name; /* Name of files used for charts. */
 
+    bool auto_width;            /* Use viewwidth as page width? */
+    bool auto_length;           /* Use viewlength as page width? */
     int page_length;           /* Page length before subtracting margins. */
     int top_margin;            /* Top margin in lines. */
     int bottom_margin;         /* Bottom margin in lines. */
@@ -129,6 +132,7 @@ struct ascii_driver_ext
 
 static void ascii_flush (struct outp_driver *);
 static int get_default_box_char (size_t idx);
+static bool update_page_size (struct outp_driver *, bool issue_error);
 static bool handle_option (struct outp_driver *this, const char *key,
                            const struct string *val);
 
@@ -154,6 +158,8 @@ ascii_open_driver (struct outp_driver *this, struct substring options)
   x->tab_width = 8;
   x->chart_file_name = pool_strdup (x->pool, "pspp-#.png");
   x->chart_type = pool_strdup (x->pool, "png");
+  x->auto_width = false;
+  x->auto_length = false;
   x->page_length = 66;
   x->top_margin = 2;
   x->bottom_margin = 2;
@@ -171,19 +177,8 @@ ascii_open_driver (struct outp_driver *this, struct substring options)
   if (!outp_parse_options (options, handle_option, this))
     goto error;
 
-  this->length = x->page_length - x->top_margin - x->bottom_margin - 1;
-  if (x->headers)
-    this->length -= 3;
-
-  if (this->width < 59 || this->length < 15)
-    {
-      error (0, 0,
-             _("ascii: page excluding margins and headers "
-               "must be at least 59 characters wide by 15 lines long, but as "
-               "configured is only %d characters by %d lines"),
-             this->width, this->length);
-      return false;
-    }
+  if (!update_page_size (this, true))
+    goto error;
 
   for (i = 0; i < LNS_COUNT; i++)
     if (x->box[i] == NULL)
@@ -233,6 +228,43 @@ get_default_box_char (size_t idx)
     }
 }
 
+/* Re-calculates the page width and length based on settings,
+   margins, and, if "auto" is set, the size of the user's
+   terminal window or GUI output window. */
+static bool
+update_page_size (struct outp_driver *this, bool issue_error)
+{
+  struct ascii_driver_ext *x = this->ext;
+  int margins = x->top_margin + x->bottom_margin + 1 + (x->headers ? 3 : 0);
+
+  if (x->auto_width)
+    this->width = get_viewwidth ();
+  if (x->auto_length)
+    x->page_length = get_viewlength ();
+
+  this->length = x->page_length - margins;
+
+  if (this->width < 59 || this->length < 15)
+    {
+      if (issue_error)
+        error (0, 0,
+               _("ascii: page excluding margins and headers "
+                 "must be at least 59 characters wide by 15 lines long, but "
+                 "as configured is only %d characters by %d lines"),
+             this->width, this->length);
+      if (this->width < 59)
+        this->width = 59;
+      if (this->length < 15)
+        {
+          this->length = 15;
+          x->page_length = this->length + margins;
+        }
+      return false;
+    }
+
+  return true;
+}
+
 static bool
 ascii_close_driver (struct outp_driver *this)
 {
@@ -251,7 +283,7 @@ enum
     boolean_arg,
     emphasis_arg,
     nonneg_int_arg,
-    pos_int_arg,
+    page_size_arg,
     string_arg
   };
 
@@ -264,8 +296,8 @@ static const struct outp_option option_tab[] =
 
     {"emphasis", emphasis_arg, 0},
 
-    {"length", pos_int_arg, 0},
-    {"width", pos_int_arg, 1},
+    {"length", page_size_arg, 0},
+    {"width", page_size_arg, 1},
 
     {"top-margin", nonneg_int_arg, 0},
     {"bottom-margin", nonneg_int_arg, 1},
@@ -311,30 +343,51 @@ handle_option (struct outp_driver *this, const char *key,
     case -1:
       error (0, 0, _("ascii: unknown parameter `%s'"), key);
       break;
-    case pos_int_arg:
+    case page_size_arg:
       {
        char *tail;
        int arg;
 
-       errno = 0;
-       arg = strtol (value, &tail, 0);
-       if (arg < 1 || errno == ERANGE || *tail)
-         {
-           error (0, 0, _("ascii: positive integer required as `%s' value"),
-                   key);
-           break;
-         }
-       switch (subcat)
-         {
-         case 0:
-           x->page_length = arg;
-           break;
-         case 1:
-           this->width = arg;
-           break;
-         default:
-           NOT_REACHED ();
-         }
+        if (ss_equals_case (ds_ss (val), ss_cstr ("auto")))
+          {
+            if (!(this->device & OUTP_DEV_SCREEN))
+              {
+                /* We only let `screen' devices have `auto'
+                   length or width because output to such devices
+                   is flushed before each new command.  Resizing
+                   a device in the middle of output seems like a
+                   bad idea. */
+                error (0, 0, _("ascii: only screen devices may have `auto' "
+                               "length or width"));
+              }
+            else if (subcat == 0)
+              x->auto_length = true;
+            else
+              x->auto_width = true;
+          }
+        else
+          {
+            errno = 0;
+            arg = strtol (value, &tail, 0);
+            if (arg < 1 || errno == ERANGE || *tail)
+              {
+                error (0, 0, _("ascii: positive integer required as "
+                               "`%s' value"),
+                       key);
+                break;
+              }
+            switch (subcat)
+              {
+              case 0:
+                x->page_length = arg;
+                break;
+              case 1:
+                this->width = arg;
+                break;
+              default:
+                NOT_REACHED ();
+              }
+          }
       }
       break;
     case emphasis_arg:
@@ -448,6 +501,8 @@ ascii_open_page (struct outp_driver *this)
   struct ascii_driver_ext *x = this->ext;
   int i;
 
+  update_page_size (this, false);
+
   if (x->file == NULL)
     {
       x->file = fn_open (x->file_name, x->append ? "a" : "w");
index 1e96e790b9c8b401e1d6fc72737724a76c7578a5..c626af0aae1cbebfed7a56913aec517fdbb79e3a 100644 (file)
@@ -1,3 +1,25 @@
+2007-09-25  Ben Pfaff  <blp@gnu.org>
+
+       Patch #6210: implement ability to resize output device parameters
+       to fit terminal window size as it changes.  Reviewed by John
+       Darrington.
+       
+       * automake.mk (src_ui_terminal_libui_a_SOURCES): Add new files.
+
+       * terminal.c: New file.
+
+       * terminal.h: New file.
+
+       * main.c (main): No need to set up SIGWINCH handler any longer.
+       But we do need to call terminal_init.
+       (set_fallback_viewport): Move to terminal.c.
+       [HAVE_LIBNCURSES] (get_termcap_viewport): Ditto.
+       [!HAVE_LIBNCURSES] (get_termcap_viewport): Ditto.
+
+       * read-line.c (readln_read): After the first line of a command,
+       call terminal_check_size to allow it to re-detect the terminal
+       size.
+
 2007-09-24  Ben Pfaff  <blp@gnu.org>
 
        Patch #6210.  Reviewed by John Darrington.
index dfc52454eaad07a8513141361a5a4968186fa136..a6ea104a4cb8ceeff0f73bb21f8e56c10a7503f7 100644 (file)
@@ -9,7 +9,9 @@ src_ui_terminal_libui_a_SOURCES = \
        src/ui/terminal/read-line.h \
        src/ui/terminal/main.c \
        src/ui/terminal/msg-ui.c \
-       src/ui/terminal/msg-ui.h
+       src/ui/terminal/msg-ui.h \
+       src/ui/terminal/terminal.c \
+       src/ui/terminal/terminal.h      
 
 src_ui_terminal_libui_a_CFLAGS = -DINSTALLDIR=\"$(bindir)\"
 
index ad76cb1a43e361d467b4379d293076ddc97bdb54..e3d3dbd7df5d7aaf92daa164ef566eea5dc8abd9 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
 
 #include <config.h>
 
+#include <locale.h>
 #include <signal.h>
 #include <stdio.h>
-
-#include <ui/debugger.h>
-#include "command-line.h"
-#include "msg-ui.h"
-#include "progname.h"
-#include "read-line.h"
+#include <stdlib.h>
+#if HAVE_FPU_CONTROL_H
+#include <fpu_control.h>
+#endif
+#if HAVE_FENV_H
+#include <fenv.h>
+#endif
+#if HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
 
 #include <data/dictionary.h>
 #include <data/file-handle-def.h>
 #include <libpspp/version.h>
 #include <math/random.h>
 #include <output/output.h>
+#include <ui/debugger.h>
+#include <ui/terminal/command-line.h>
+#include <ui/terminal/msg-ui.h>
+#include <ui/terminal/read-line.h>
+#include <ui/terminal/terminal.h>
 
-#if HAVE_FPU_CONTROL_H
-#include <fpu_control.h>
-#endif
-
-#if HAVE_LOCALE_H
-#include <locale.h>
-#endif
-
-#if HAVE_FENV_H
-#include <fenv.h>
-#endif
-
-#if HAVE_IEEEFP_H
-#include <ieeefp.h>
-#endif
+#include "progname.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-#include <stdlib.h>
 
 static void i18n_init (void);
 static void fpu_init (void);
@@ -78,23 +73,18 @@ static struct dataset * the_dataset = NULL;
 static struct lexer *the_lexer;
 static struct source_stream *the_source_stream ;
 
-static int view_length = -1;
-static int view_width = -1;
-
-static void get_termcap_viewport (int);
-
-
 /* Program entry point. */
 int
 main (int argc, char **argv)
 {
+  int *view_width_p, *view_length_p;
+
+  set_program_name (argv[0]);
+
   signal (SIGABRT, bug_handler);
   signal (SIGSEGV, bug_handler);
   signal (SIGFPE, bug_handler);
   signal (SIGINT, interrupt_handler);
-  signal (SIGWINCH, get_termcap_viewport);
-
-  set_program_name (argv[0]);
 
   i18n_init ();
   fpu_init ();
@@ -110,8 +100,8 @@ main (int argc, char **argv)
                          );
   prompt_init ();
   readln_initialize ();
-  get_termcap_viewport (0);
-  settings_init (&view_width, &view_length);
+  terminal_init (&view_width_p, &view_length_p);
+  settings_init (view_width_p, view_length_p);
   random_init ();
 
   the_dataset = create_dataset ();
@@ -231,73 +221,3 @@ terminate (bool success)
     }
   exit (success ? EXIT_SUCCESS : EXIT_FAILURE);
 }
-
-\f
-#include "error.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-/* If view_width or view_length has not yet been set to a
-   reasonable value, takes a guess. */
-static void
-set_fallback_viewport (void)
-{
-  if (view_width <= 0)
-    {
-      if (getenv ("COLUMNS") != NULL)
-        view_width = atoi (getenv ("COLUMNS"));
-      if (view_width <= 0)
-        view_width = 79;
-    }
-
-  if (view_length <= 0)
-    {
-      if (getenv ("LINES") != NULL)
-        view_length = atoi (getenv ("LINES"));
-      if (view_length <= 0)
-        view_length = 24;
-    }
-}
-
-/* Code that interfaces to ncurses.  This must be at the very end
-   of this file because curses.h redefines "bool" on some systems
-   (e.g. OpenBSD), causing declaration mismatches with functions
-   that have parameters or return values of type "bool". */
-#if HAVE_LIBNCURSES
-#include <curses.h>
-#include <term.h>
-
-static void
-get_termcap_viewport (int sig UNUSED)
-{
-  char term_buffer [16384];
-
-  if (getenv ("TERM") != NULL)
-    {
-      if (tgetent (term_buffer, getenv ("TERM")) > 0)
-        {
-          if (tgetnum ("li") > 0)
-            view_length = tgetnum ("li");
-          if (tgetnum ("co") > 1)
-            view_width = tgetnum ("co") - 1;
-        }
-      else
-        error (0, 0, _("could not access definition for terminal `%s'"),
-               getenv ("TERM"));
-    }
-
-  set_fallback_viewport ();
-}
-
-#else /* !HAVE_LIBNCURSES */
-
-static void
-get_termcap_viewport (int sig UNUSED)
-{
-  set_fallback_viewport ();
-}
-
-#endif /* !HAVE_LIBNCURSES */
-
-
index 626b06353392f75c6941c6e1ac1e30f6096a0ef2..493a3d63cf5bd6399e7ea90de6081ae59d967e5c 100644 (file)
@@ -34,6 +34,7 @@
 #include <language/prompt.h>
 #include <output/journal.h>
 #include <output/manager.h>
+#include <ui/terminal/terminal.h>
 
 #include "xalloc.h"
 
@@ -143,6 +144,7 @@ readln_read (struct string *line, enum prompt_style style)
 #if HAVE_READLINE
   char *string;
 #endif
+  bool eof;
 
   assert (initialised);
 
@@ -159,14 +161,14 @@ readln_read (struct string *line, enum prompt_style style)
                                       : dont_complete);
   string = readline (prompt);
   if (string == NULL)
-    return false;
+    eof = true;
   else
     {
       if (string[0])
         add_history (string);
       ds_assign_cstr (line, string);
       free (string);
-      return true;
+      eof = false;
     }
 #else
   fputs (prompt, stdout);
@@ -174,13 +176,23 @@ readln_read (struct string *line, enum prompt_style style)
   if (ds_read_line (line, stdin))
     {
       ds_chomp (line, '\n');
-      return true;
+      eof = false;
     }
   else
-    return false;
+    eof = true;
 #endif
-}
 
+  /* Check whether the size of the window has changed, so that
+     the output drivers can adjust their settings as needed.  We
+     only do this for the first line of a command, as it's
+     possible that the output drivers are actually in use
+     afterward, and we don't want to confuse them in the middle
+     of output. */
+  if (style == PROMPT_FIRST)
+    terminal_check_size ();
+
+  return !eof;
+}
 
 static void
 readln_close (struct getl_interface *i)
diff --git a/src/ui/terminal/terminal.c b/src/ui/terminal/terminal.c
new file mode 100644 (file)
index 0000000..9f37182
--- /dev/null
@@ -0,0 +1,92 @@
+/* PSPP - a program for statistical analysis.
+   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
+   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 <ui/terminal/terminal.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <libpspp/compiler.h>
+
+#include "error.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+static int view_width = -1;
+static int view_length = -1;
+
+/* Initializes the terminal interface by determining the size of
+   the user's terminal.  Stores a pointer to the size variables
+   in *VIEW_WIDTH_P and *VIEW_LENGTH_P. */
+void
+terminal_init (int **view_width_p, int **view_length_p)
+{
+  *view_width_p = &view_width;
+  *view_length_p = &view_length;
+  terminal_check_size ();
+}
+
+/* Code that interfaces to ncurses.  This must be at the very end
+   of this file because curses.h redefines "bool" on some systems
+   (e.g. OpenBSD), causing declaration mismatches with functions
+   that have parameters or return values of type "bool". */
+#if HAVE_LIBNCURSES
+#include <curses.h>
+#include <term.h>
+#endif
+
+/* Determines the size of the terminal, if possible, or at least
+   takes an educated guess. */
+void
+terminal_check_size (void)
+{
+#if HAVE_LIBNCURSES
+  if (getenv ("TERM") != NULL)
+    {
+      char term_buffer [16384];
+
+      if (tgetent (term_buffer, getenv ("TERM")) > 0)
+        {
+          if (tgetnum ("li") > 0)
+            view_length = tgetnum ("li");
+          if (tgetnum ("co") > 1)
+            view_width = tgetnum ("co") - 1;
+        }
+      else
+        error (0, 0, _("could not access definition for terminal `%s'"),
+               getenv ("TERM"));
+    }
+#endif
+
+  if (view_width <= 0)
+    {
+      if (getenv ("COLUMNS") != NULL)
+        view_width = atoi (getenv ("COLUMNS"));
+      if (view_width <= 0)
+        view_width = 79;
+    }
+
+  if (view_length <= 0)
+    {
+      if (getenv ("LINES") != NULL)
+        view_length = atoi (getenv ("LINES"));
+      if (view_length <= 0)
+        view_length = 24;
+    }
+}
diff --git a/src/ui/terminal/terminal.h b/src/ui/terminal/terminal.h
new file mode 100644 (file)
index 0000000..1260e93
--- /dev/null
@@ -0,0 +1,23 @@
+/* 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/>. */
+
+#ifndef UI_TERMINAL_TERMINAL_H
+#define UI_TERMINAL_TERMINAL_H 1
+
+void terminal_init (int **view_width_p, int **view_length_p);
+void terminal_check_size (void);
+
+#endif /* ui/terminal/terminal.h */