From: Bruno Haible Date: Tue, 12 Mar 2019 18:28:14 +0000 (+0100) Subject: libtextstyle: New function term_ostream_flush_to_current_style. X-Git-Tag: v0.20~140 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=63b30165deacfea29860d23cc5fbe8c7ffc7da8d;p=thirdparty%2Fgettext.git libtextstyle: New function term_ostream_flush_to_current_style. * gnulib-local/lib/term-ostream.oo.h (struct term_ostream): Add method flush_to_current_style. * gnulib-local/lib/term-ostream.oo.c (struct term_ostream): Add fields default_attr, active_attr, non_default_active. (out_attr_change): Remove second argument. Update active_attr. (activate_non_default_attr, deactivate_non_default_attr, activate_default_attr): New functions, extracted from output_buffer. (output_buffer): Use them. Add a second argument. (term_ostream::write_mem, term_ostream::flush): Update output_buffer calls. (term_ostream::free): Add an assertion. (term_ostream::flush_to_current_style): New method. (term_ostream_create): Initialize the fields default_attr, active_attr, non_default_active. * libtextstyle/lib/textstyle.h (term_ostream_flush_to_current_style): New declaration. * libtextstyle/doc/libtextstyle.texi (The term_ostream class): Document term_ostream_flush_to_current_style. * libtextstyle/NEWS: Mention the change. --- diff --git a/gnulib-local/lib/term-ostream.oo.c b/gnulib-local/lib/term-ostream.oo.c index 797acbc44..517b67bbb 100644 --- a/gnulib-local/lib/term-ostream.oo.c +++ b/gnulib-local/lib/term-ostream.oo.c @@ -971,7 +971,17 @@ fields: bool supports_weight; bool supports_posture; bool supports_underline; - /* Variable state. */ + /* Variable state, representing past output. */ + attributes_t default_attr; /* Default simplified attributes of the + terminal. */ + attributes_t active_attr; /* Simplified attributes that we have set + on the terminal. */ + bool non_default_active; /* True if activate_non_default_attr() + is in effect. + active_attr != default_attr implies + non_default_active == true, + but not the opposite! */ + /* Variable state, representing future output. */ char *buffer; /* Buffer for the current line. */ attributes_t *attrbuffer; /* Buffer for the simplified attributes; same length as buffer. */ @@ -1138,11 +1148,12 @@ out_char (int c) return 0; } -/* Output escape sequences to switch from OLD_ATTR to NEW_ATTR. */ +/* Output escape sequences to switch from STREAM->ACTIVE_ATTR to NEW_ATTR, + and update STREAM->ACTIVE_ATTR. */ static void -out_attr_change (term_ostream_t stream, - attributes_t old_attr, attributes_t new_attr) +out_attr_change (term_ostream_t stream, attributes_t new_attr) { + attributes_t old_attr = stream->active_attr; bool cleared_attributes; /* We don't know the default colors of the terminal. The only way to switch @@ -1422,49 +1433,18 @@ out_attr_change (term_ostream_t stream, assert (new_attr.underline == UNDERLINE_ON); tputs (stream->enter_underline_mode, 1, out_char); } + + /* Keep track of the active attributes. */ + stream->active_attr = new_attr; } -/* Output the buffered line atomically. - The terminal is assumed to have the default state (regarding colors and - attributes) before this call. It is left in default state after this - call (regardless of stream->curr_attr). */ +/* Prepare for activating some non-default attributes. + Note: This may block some signals. */ static void -output_buffer (term_ostream_t stream) +activate_non_default_attr (term_ostream_t stream) { - attributes_t default_attr; - attributes_t attr; - const char *cp; - const attributes_t *ap; - size_t len; - size_t n; - - default_attr.color = COLOR_DEFAULT; - default_attr.bgcolor = COLOR_DEFAULT; - default_attr.weight = WEIGHT_DEFAULT; - default_attr.posture = POSTURE_DEFAULT; - default_attr.underline = UNDERLINE_DEFAULT; - - attr = default_attr; - - cp = stream->buffer; - ap = stream->attrbuffer; - len = stream->buflen; - - /* See how much we can output without blocking signals. */ - for (n = 0; n < len && equal_attributes (ap[n], attr); n++) - ; - if (n > 0) - { - if (full_write (stream->fd, cp, n) < n) - error (EXIT_FAILURE, errno, _("error writing to %s"), stream->filename); - cp += n; - ap += n; - len -= n; - } - if (len > 0) + if (!stream->non_default_active) { - int error_code = 0; - /* Block fatal signals, so that a SIGINT or similar doesn't interrupt us without the possibility of restoring the terminal's state. */ block_fatal_signals (); @@ -1493,44 +1473,116 @@ output_buffer (term_ostream_t stream) out_fd = stream->fd; out_filename = stream->filename; - while (len > 0) + stream->non_default_active = true; + } +} + +/* Deactivate the non-default attributes mode. + Note: This may unblock some signals. */ +static void +deactivate_non_default_attr (term_ostream_t stream) +{ + if (stream->non_default_active) + { + /* Disable the exit handler. */ + out_fd = -1; + out_filename = NULL; + + /* Unblock fatal and stopping signals. */ + unblock_stopping_signals (); + unblock_fatal_signals (); + + stream->non_default_active = false; + } +} + +/* Activate the default attributes. */ +static void +activate_default_attr (term_ostream_t stream) +{ + /* Switch back to the default attributes. */ + out_attr_change (stream, stream->default_attr); + + deactivate_non_default_attr (stream); +} + +/* Output the buffered line atomically. + The terminal is left in the the state (regarding colors and attributes) + represented by the simplified attributes goal_attr. */ +static void +output_buffer (term_ostream_t stream, attributes_t goal_attr) +{ + const char *cp; + const attributes_t *ap; + size_t len; + size_t n; + + cp = stream->buffer; + ap = stream->attrbuffer; + len = stream->buflen; + + /* See how much we can output without blocking signals. */ + for (n = 0; n < len && equal_attributes (ap[n], stream->active_attr); n++) + ; + if (n > 0) + { + if (full_write (stream->fd, cp, n) < n) + { + int error_code = errno; + /* Do output to stderr only after we have switched back to the + default attributes. Otherwise this output may come out with + the wrong text attributes. */ + if (!equal_attributes (stream->active_attr, stream->default_attr)) + activate_default_attr (stream); + error (EXIT_FAILURE, error_code, _("error writing to %s"), + stream->filename); + } + cp += n; + ap += n; + len -= n; + } + if (len > 0) + { + if (!equal_attributes (*ap, stream->default_attr)) + activate_non_default_attr (stream); + + do { /* Activate the attributes in *ap. */ - out_attr_change (stream, attr, *ap); - attr = *ap; + out_attr_change (stream, *ap); /* See how many characters we can output without further attribute changes. */ - for (n = 1; n < len && equal_attributes (ap[n], attr); n++) + for (n = 1; n < len && equal_attributes (ap[n], stream->active_attr); n++) ; if (full_write (stream->fd, cp, n) < n) { - error_code = errno; - break; + int error_code = errno; + /* Do output to stderr only after we have switched back to the + default attributes. Otherwise this output may come out with + the wrong text attributes. */ + if (!equal_attributes (stream->active_attr, stream->default_attr)) + activate_default_attr (stream); + error (EXIT_FAILURE, error_code, _("error writing to %s"), + stream->filename); } cp += n; ap += n; len -= n; } - - /* Switch back to the default attributes. */ - out_attr_change (stream, attr, default_attr); - - /* Disable the exit handler. */ - out_fd = -1; - out_filename = NULL; - - /* Unblock fatal and stopping signals. */ - unblock_stopping_signals (); - unblock_fatal_signals (); - - /* Do output to stderr only after we have switched back to the default - attributes. Otherwise this output may come out with the wrong text - attributes. */ - if (error_code != 0) - error (EXIT_FAILURE, error_code, _("error writing to %s"), - stream->filename); + while (len > 0); } stream->buflen = 0; + + /* Before changing to goal_attr, we may need to enable the non-default + attributes mode. */ + if (!equal_attributes (goal_attr, stream->default_attr)) + activate_non_default_attr (stream); + /* Change to goal_attr. */ + if (!equal_attributes (goal_attr, stream->active_attr)) + out_attr_change (stream, goal_attr); + /* When we can deactivate the non-default attributes mode, do so. */ + if (equal_attributes (goal_attr, stream->default_attr)) + deactivate_non_default_attr (stream); } /* Implementation of ostream_t methods. */ @@ -1596,7 +1648,7 @@ term_ostream::write_mem (term_ostream_t stream, const void *data, size_t len) if (newline != NULL) { - output_buffer (stream); + output_buffer (stream, stream->default_attr); if (full_write (stream->fd, "\n", 1) < 1) error (EXIT_FAILURE, errno, _("error writing to %s"), stream->filename); @@ -1611,7 +1663,7 @@ term_ostream::write_mem (term_ostream_t stream, const void *data, size_t len) static void term_ostream::flush (term_ostream_t stream, ostream_flush_scope_t scope) { - output_buffer (stream); + output_buffer (stream, stream->default_attr); if (scope == FLUSH_ALL) { /* For streams connected to a disk file: */ @@ -1627,6 +1679,9 @@ static void term_ostream::free (term_ostream_t stream) { term_ostream_flush (stream, FLUSH_THIS_STREAM); + /* Verify that the non-default attributes mode is turned off. */ + if (stream->non_default_active) + abort (); free (stream->filename); if (stream->set_a_foreground != NULL) free (stream->set_a_foreground); @@ -1721,6 +1776,12 @@ term_ostream::set_underline (term_ostream_t stream, term_underline_t underline) stream->simp_attr = simplify_attributes (stream, stream->curr_attr); } +static void +term_ostream::flush_to_current_style (term_ostream_t stream) +{ + output_buffer (stream, stream->simp_attr); +} + /* Constructor. */ static inline char * @@ -1928,12 +1989,24 @@ term_ostream_create (int fd, const char *filename, ttyctl_t tty_control) stream->buflen = 0; /* Initialize the current attributes. */ - stream->curr_attr.color = COLOR_DEFAULT; - stream->curr_attr.bgcolor = COLOR_DEFAULT; - stream->curr_attr.weight = WEIGHT_DEFAULT; - stream->curr_attr.posture = POSTURE_DEFAULT; - stream->curr_attr.underline = UNDERLINE_DEFAULT; - stream->simp_attr = simplify_attributes (stream, stream->curr_attr); + { + attributes_t assumed_default; + attributes_t simplified_default; + + assumed_default.color = COLOR_DEFAULT; + assumed_default.bgcolor = COLOR_DEFAULT; + assumed_default.weight = WEIGHT_DEFAULT; + assumed_default.posture = POSTURE_DEFAULT; + assumed_default.underline = UNDERLINE_DEFAULT; + + simplified_default = simplify_attributes (stream, assumed_default); + + stream->default_attr = simplified_default; + stream->active_attr = simplified_default; + stream->non_default_active = false; + stream->curr_attr = assumed_default; + stream->simp_attr = simplified_default; + } /* Register an exit handler. */ { diff --git a/gnulib-local/lib/term-ostream.oo.h b/gnulib-local/lib/term-ostream.oo.h index 336aff6b9..5e2fd7de8 100644 --- a/gnulib-local/lib/term-ostream.oo.h +++ b/gnulib-local/lib/term-ostream.oo.h @@ -87,6 +87,14 @@ methods: term_underline_t get_underline (term_ostream_t stream); void set_underline (term_ostream_t stream, term_underline_t underline); + + /* Like term_ostream_flush (first_arg, FLUSH_THIS_STREAM), except that it + leaves the terminal with the current text attributes enabled, instead of + with the default text attributes. + After calling this function, you can output strings without newlines(!) + to the underlying file descriptor, and they will be rendered like strings + passed to 'ostream_write_mem' or 'ostream_write_str'. */ + void flush_to_current_style (term_ostream_t stream); }; /* The amount of control to take over the underlying tty in order to avoid diff --git a/libtextstyle/NEWS b/libtextstyle/NEWS index ec3064ae2..088704511 100644 --- a/libtextstyle/NEWS +++ b/libtextstyle/NEWS @@ -1,6 +1,8 @@ New in 0.6: * The ostream_t operation 'flush' now takes an additional argument, of type ostream_flush_scope_t. +* The term_ostream_t type supports a new function + term_ostream_flush_to_current_style. New in 0.5: diff --git a/libtextstyle/doc/libtextstyle.texi b/libtextstyle/doc/libtextstyle.texi index 764fd74b0..6f62281ab 100644 --- a/libtextstyle/doc/libtextstyle.texi +++ b/libtextstyle/doc/libtextstyle.texi @@ -809,6 +809,16 @@ Gets/sets the font posture. Gets/sets the text underline decoration. @end deftypefn +@deftypefn Function void term_ostream_flush_to_current_style (term_ostream_t@tie{}@var{stream}) +This function acts like @code{ostream_flush (@var{stream}, FLUSH_THIS_STREAM)}, +except that it leaves the terminal with the current text attributes enabled, +instead of with the default text attributes. + +After calling this function, you can output strings without newlines(!) to the +underlying file descriptor, and they will be rendered like strings passed to +@code{ostream_write_mem} or @code{ostream_write_str}. +@end deftypefn + @node The html_ostream class @subsubsection The @code{html_ostream} class diff --git a/libtextstyle/lib/textstyle.h b/libtextstyle/lib/textstyle.h index f17766780..013a8b41b 100644 --- a/libtextstyle/lib/textstyle.h +++ b/libtextstyle/lib/textstyle.h @@ -219,6 +219,13 @@ extern term_posture_t term_ostream_get_posture (term_ostream_t first_arg); extern void term_ostream_set_posture (term_ostream_t first_arg, term_posture_t posture); extern term_underline_t term_ostream_get_underline (term_ostream_t first_arg); extern void term_ostream_set_underline (term_ostream_t first_arg, term_underline_t underline); +/* Like term_ostream_flush (first_arg, FLUSH_THIS_STREAM), except that it + leaves the terminal with the current text attributes enabled, instead of + with the default text attributes. + After calling this function, you can output strings without newlines(!) + to the underlying file descriptor, and they will be rendered like strings + passed to 'ostream_write_mem' or 'ostream_write_str'. */ +extern void term_ostream_flush_to_current_style (term_ostream_t first_arg); #ifdef __cplusplus } #endif