From bce579d144b66ca2eee18f6d27d847285a96d7b9 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 26 Sep 2007 04:24:07 +0000 Subject: [PATCH] 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. * 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 | 6 ++ config/devices | 3 +- doc/configuring.texi | 12 ++-- src/output/ChangeLog | 14 ++++ src/output/ascii.c | 131 +++++++++++++++++++++++++----------- src/ui/terminal/ChangeLog | 22 ++++++ src/ui/terminal/automake.mk | 4 +- src/ui/terminal/main.c | 128 +++++++---------------------------- src/ui/terminal/read-line.c | 22 ++++-- src/ui/terminal/terminal.c | 92 +++++++++++++++++++++++++ src/ui/terminal/terminal.h | 23 +++++++ 11 files changed, 303 insertions(+), 154 deletions(-) create mode 100644 src/ui/terminal/terminal.c create mode 100644 src/ui/terminal/terminal.h diff --git a/config/ChangeLog b/config/ChangeLog index 27cb2b33..dbf6c3ad 100644 --- a/config/ChangeLog +++ b/config/ChangeLog @@ -1,3 +1,9 @@ +2007-09-25 Ben Pfaff + + * 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 Bug #21128. Reviewed by John Darrington. diff --git a/config/devices b/config/devices index 7da8eac8..48513fe6 100644 --- a/config/devices +++ b/config/devices @@ -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 \ diff --git a/doc/configuring.texi b/doc/configuring.texi index 18d24cac..164d9ab1 100644 --- a/doc/configuring.texi +++ b/doc/configuring.texi @@ -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} diff --git a/src/output/ChangeLog b/src/output/ChangeLog index adabbcde..0073124e 100644 --- a/src/output/ChangeLog +++ b/src/output/ChangeLog @@ -1,3 +1,17 @@ +2007-09-25 Ben Pfaff + + 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 Bug #21128. Reviewed by John Darrington. diff --git a/src/output/ascii.c b/src/output/ascii.c index bdb02dbf..f2dff490 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -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"); diff --git a/src/ui/terminal/ChangeLog b/src/ui/terminal/ChangeLog index 1e96e790..c626af0a 100644 --- a/src/ui/terminal/ChangeLog +++ b/src/ui/terminal/ChangeLog @@ -1,3 +1,25 @@ +2007-09-25 Ben Pfaff + + 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 Patch #6210. Reviewed by John Darrington. diff --git a/src/ui/terminal/automake.mk b/src/ui/terminal/automake.mk index dfc52454..a6ea104a 100644 --- a/src/ui/terminal/automake.mk +++ b/src/ui/terminal/automake.mk @@ -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)\" diff --git a/src/ui/terminal/main.c b/src/ui/terminal/main.c index ad76cb1a..e3d3dbd7 100644 --- a/src/ui/terminal/main.c +++ b/src/ui/terminal/main.c @@ -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 @@ -16,14 +16,19 @@ #include +#include #include #include - -#include -#include "command-line.h" -#include "msg-ui.h" -#include "progname.h" -#include "read-line.h" +#include +#if HAVE_FPU_CONTROL_H +#include +#endif +#if HAVE_FENV_H +#include +#endif +#if HAVE_IEEEFP_H +#include +#endif #include #include @@ -42,27 +47,17 @@ #include #include #include +#include +#include +#include +#include +#include -#if HAVE_FPU_CONTROL_H -#include -#endif - -#if HAVE_LOCALE_H -#include -#endif - -#if HAVE_FENV_H -#include -#endif - -#if HAVE_IEEEFP_H -#include -#endif +#include "progname.h" #include "gettext.h" #define _(msgid) gettext (msgid) -#include 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); } - - -#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 -#include - -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 */ - - diff --git a/src/ui/terminal/read-line.c b/src/ui/terminal/read-line.c index 626b0635..493a3d63 100644 --- a/src/ui/terminal/read-line.c +++ b/src/ui/terminal/read-line.c @@ -34,6 +34,7 @@ #include #include #include +#include #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 index 00000000..9f371821 --- /dev/null +++ b/src/ui/terminal/terminal.c @@ -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 . */ + +#include + +#include + +#include +#include + +#include + +#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 +#include +#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 index 00000000..1260e932 --- /dev/null +++ b/src/ui/terminal/terminal.h @@ -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 . */ + +#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 */ -- 2.30.2