Programs that use the module 'libtextstyle' and still want to be able to build when no libtextstyle is installed need to use #if HAVE_LIBTEXTSTYLE in many places.
The module 'libtextstyle-optional' greatly reduces the need to use that much conditional code (assuming the program's developer accepts to use ostream_t types in unconditional code). Akim Demaille confirmed that this module is useful, so I am adding it. 2019-03-19 Bruno Haible <br...@clisp.org> libtextstyle-optional: New module. * lib/textstyle.in.h: New file, based on libtextstyle's textstyle.h. * m4/libtextstyle-optional.m4: New file, based on m4/libtextstyle.m4. * modules/libtextstyle-optional: New file. libtextstyle-optional: Add tests. * tests/test-libtextstyle.c: New file, based on libtextstyle's adhoc-tests/hello.c. * tests/test-libtextstyle-default.css: New file, copied from libtextstyle's adhoc-tests/hello-default.css. * modules/libtextstyle-optional-tests: New file.
>From c23dae8c0231543a241bd54f6e5af0f348f70d99 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Wed, 20 Mar 2019 00:35:11 +0100 Subject: [PATCH 1/2] libtextstyle-optional: New module. * lib/textstyle.in.h: New file, based on libtextstyle's textstyle.h. * m4/libtextstyle-optional.m4: New file, based on m4/libtextstyle.m4. * modules/libtextstyle-optional: New file. --- ChangeLog | 7 + lib/textstyle.in.h | 377 ++++++++++++++++++++++++++++++++++++++++++ m4/libtextstyle-optional.m4 | 30 ++++ modules/libtextstyle-optional | 45 +++++ 4 files changed, 459 insertions(+) create mode 100644 lib/textstyle.in.h create mode 100644 m4/libtextstyle-optional.m4 create mode 100644 modules/libtextstyle-optional diff --git a/ChangeLog b/ChangeLog index 8a4c5f3..af9d7f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2019-03-19 Bruno Haible <br...@clisp.org> + libtextstyle-optional: New module. + * lib/textstyle.in.h: New file, based on libtextstyle's textstyle.h. + * m4/libtextstyle-optional.m4: New file, based on m4/libtextstyle.m4. + * modules/libtextstyle-optional: New file. + +2019-03-19 Bruno Haible <br...@clisp.org> + c-stack: Make signal handlers more reliable. * lib/c-stack.c (progname): New variable. (die): Use it. diff --git a/lib/textstyle.in.h b/lib/textstyle.in.h new file mode 100644 index 0000000..65fa670 --- /dev/null +++ b/lib/textstyle.in.h @@ -0,0 +1,377 @@ +/* Dummy replacement for part of the public API of the libtextstyle library. + Copyright (C) 2006-2007, 2019 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 <https://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <br...@clisp.org>, 2019. */ + +/* This file is used as replacement when libtextstyle with its include file + <textstyle.h> is not found. + It supports the essential API and implements it in a way that does not + provide text styling. That is, it produces plain text output via <stdio.h> + FILE objects. + Thus, it allows a package to be build with or without a dependency to + libtextstyle, with very few occurrences of '#if HAVE_LIBTEXTSTYLE'. + + Restriction: + It assumes that freopen() is not being called on stdout and stderr. */ + +#ifndef _TEXTSTYLE_H +#define _TEXTSTYLE_H + +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#if HAVE_TCDRAIN +# include <termios.h> +#endif + +/* ----------------------------- From ostream.h ----------------------------- */ + +/* Describes the scope of a flush operation. */ +typedef enum +{ + /* Flushes buffers in this ostream_t. + Use this value if you want to write to the underlying ostream_t. */ + FLUSH_THIS_STREAM = 0, + /* Flushes all buffers in the current process. + Use this value if you want to write to the same target through a + different file descriptor or a FILE stream. */ + FLUSH_THIS_PROCESS = 1, + /* Flushes buffers in the current process and attempts to flush the buffers + in the kernel. + Use this value so that some other process (or the kernel itself) + may write to the same target. */ + FLUSH_ALL = 2 +} ostream_flush_scope_t; + + +/* An output stream is an object to which one can feed a sequence of bytes. */ + +typedef FILE * ostream_t; + +static inline void +ostream_write_mem (ostream_t stream, const void *data, size_t len) +{ + if (len > 0) + fwrite (data, 1, len, stream); +} + +static inline void +ostream_flush (ostream_t stream, ostream_flush_scope_t scope) +{ + fflush (stream); + if (scope == FLUSH_ALL) + { + int fd = fileno (stream); + if (fd >= 0) + { + /* For streams connected to a disk file: */ + fsync (fd); + #if HAVE_TCDRAIN + /* For streams connected to a terminal: */ + { + int retval; + + do + retval = tcdrain (fd); + while (retval < 0 && errno == EINTR); + } + #endif + } + } +} + +static inline void +ostream_free (ostream_t stream) +{ + if (stream == stdin || stream == stderr) + fflush (stream); + else + fclose (stream); +} + +static inline void +ostream_write_str (ostream_t stream, const char *string) +{ + ostream_write_mem (stream, string, strlen (string)); +} + +/* ------------------------- From styled-ostream.h ------------------------- */ + +typedef ostream_t styled_ostream_t; + +#define styled_ostream_write_mem ostream_write_mem +#define styled_ostream_flush ostream_flush +#define styled_ostream_free ostream_free + +static inline void +styled_ostream_begin_use_class (styled_ostream_t stream _GL_UNUSED, + const char *classname _GL_UNUSED) +{ +} + +static inline void +styled_ostream_end_use_class (styled_ostream_t stream _GL_UNUSED, + const char *classname _GL_UNUSED) +{ +} + +static inline void +styled_ostream_flush_to_current_style (styled_ostream_t stream _GL_UNUSED) +{ +} + +/* -------------------------- From file-ostream.h -------------------------- */ + +typedef ostream_t file_ostream_t; + +#define file_ostream_write_mem ostream_write_mem +#define file_ostream_flush ostream_flush +#define file_ostream_free ostream_free + +static inline file_ostream_t +file_ostream_create (FILE *fp) +{ + return fp; +} + +/* --------------------------- From fd-ostream.h --------------------------- */ + +typedef ostream_t fd_ostream_t; + +#define fd_ostream_write_mem ostream_write_mem +#define fd_ostream_flush ostream_flush +#define fd_ostream_free ostream_free + +static inline fd_ostream_t +fd_ostream_create (int fd, const char *filename _GL_UNUSED, + bool buffered _GL_UNUSED) +{ + if (fd == 1) + return stdout; + else if (fd == 2) + return stderr; + else + return fdopen (fd, "w"); +} + +/* -------------------------- From term-ostream.h -------------------------- */ + +typedef int term_color_t; +enum +{ + COLOR_DEFAULT = -1 /* unknown */ +}; + +typedef enum +{ + WEIGHT_NORMAL = 0, + WEIGHT_BOLD, + WEIGHT_DEFAULT = WEIGHT_NORMAL +} term_weight_t; + +typedef enum +{ + POSTURE_NORMAL = 0, + POSTURE_ITALIC, /* same as oblique */ + POSTURE_DEFAULT = POSTURE_NORMAL +} term_posture_t; + +typedef enum +{ + UNDERLINE_OFF = 0, + UNDERLINE_ON, + UNDERLINE_DEFAULT = UNDERLINE_OFF +} term_underline_t; + +typedef ostream_t term_ostream_t; + +#define term_ostream_write_mem ostream_write_mem +#define term_ostream_flush ostream_flush +#define term_ostream_free ostream_free + +static inline term_color_t +term_ostream_get_color (term_ostream_t stream _GL_UNUSED) +{ + return COLOR_DEFAULT; +} + +static inline void +term_ostream_set_color (term_ostream_t stream _GL_UNUSED, + term_color_t color _GL_UNUSED) +{ +} + +static inline term_color_t +term_ostream_get_bgcolor (term_ostream_t stream _GL_UNUSED) +{ + return COLOR_DEFAULT; +} + +static inline void +term_ostream_set_bgcolor (term_ostream_t stream _GL_UNUSED, + term_color_t color _GL_UNUSED) +{ +} + +static inline term_weight_t +term_ostream_get_weight (term_ostream_t stream _GL_UNUSED) +{ + return WEIGHT_DEFAULT; +} + +static inline void +term_ostream_set_weight (term_ostream_t stream _GL_UNUSED, + term_weight_t weight _GL_UNUSED) +{ +} + +static inline term_posture_t +term_ostream_get_posture (term_ostream_t stream _GL_UNUSED) +{ + return POSTURE_DEFAULT; +} + +static inline void +term_ostream_set_posture (term_ostream_t stream _GL_UNUSED, + term_posture_t posture _GL_UNUSED) +{ +} + +static inline term_underline_t +term_ostream_get_underline (term_ostream_t stream _GL_UNUSED) +{ + return UNDERLINE_DEFAULT; +} + +static inline void +term_ostream_set_underline (term_ostream_t stream _GL_UNUSED, + term_underline_t underline _GL_UNUSED) +{ +} + +static inline void +term_ostream_flush_to_current_style (term_ostream_t stream) +{ + fflush (stream); +} + +typedef enum +{ + TTYCTL_AUTO = 0, /* Automatic best-possible choice. */ + TTYCTL_NONE, /* No control. + Result: Garbled output can occur, and the terminal can + be left in any state when the program is interrupted. */ + TTYCTL_PARTIAL, /* Signal handling. + Result: Garbled output can occur, but the terminal will + be left in the default state when the program is + interrupted. */ + TTYCTL_FULL /* Signal handling and disabling echo and flush-upon-signal. + Result: No garbled output, and the the terminal will + be left in the default state when the program is + interrupted. */ +} ttyctl_t; + +static inline term_ostream_t +term_ostream_create (int fd, const char *filename, + ttyctl_t tty_control _GL_UNUSED) +{ + return fd_ostream_create (fd, filename, true); +} + +/* ----------------------- From term-styled-ostream.h ----------------------- */ + +typedef styled_ostream_t term_styled_ostream_t; + +#define term_styled_ostream_write_mem ostream_write_mem +#define term_styled_ostream_flush ostream_flush +#define term_styled_ostream_free ostream_free +#define term_styled_ostream_begin_use_class styled_ostream_begin_use_class +#define term_styled_ostream_end_use_class styled_ostream_end_use_class +#define term_styled_ostream_flush_to_current_style styled_ostream_flush_to_current_style + +static inline term_styled_ostream_t +term_styled_ostream_create (int fd, const char *filename, + ttyctl_t tty_control _GL_UNUSED, + const char *css_filename _GL_UNUSED) +{ + return fd_ostream_create (fd, filename, true); +} + +/* ----------------------- From html-styled-ostream.h ----------------------- */ + +typedef styled_ostream_t html_styled_ostream_t; + +static inline html_styled_ostream_t +html_styled_ostream_create (ostream_t destination, const char *css_filename) +{ + abort (); + return NULL; +} + +/* ------------------------------ From color.h ------------------------------ */ + +#define color_test_mode false + +enum color_option { color_no, color_tty, color_yes, color_html }; +#define color_mode color_no + +#define style_file_name NULL + +static inline bool +handle_color_option (const char *option _GL_UNUSED) +{ + return false; +} + +static inline void +handle_style_option (const char *option _GL_UNUSED) +{ +} + +static inline void +print_color_test (void) +{ + abort (); +} + +static inline void +style_file_prepare (const char *style_file_envvar _GL_UNUSED, + const char *stylesdir_envvar _GL_UNUSED, + const char *stylesdir_after_install _GL_UNUSED, + const char *default_style_file _GL_UNUSED) +{ +} + +/* ------------------------------ From misc.h ------------------------------ */ + +static inline styled_ostream_t +styled_ostream_create (int fd, const char *filename, + ttyctl_t tty_control _GL_UNUSED, + const char *css_filename _GL_UNUSED) +{ + return fd_ostream_create (fd, filename, true); +} + +static inline void +libtextstyle_set_failure_exit_code (int exit_code _GL_UNUSED) +{ +} + +#endif /* _TEXTSTYLE_H */ diff --git a/m4/libtextstyle-optional.m4 b/m4/libtextstyle-optional.m4 new file mode 100644 index 0000000..16c8f16 --- /dev/null +++ b/m4/libtextstyle-optional.m4 @@ -0,0 +1,30 @@ +# libtextstyle-optional.m4 serial 1 +dnl Copyright (C) 2019 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. + +dnl From Bruno Haible. + +dnl gl_LIBTEXTSTYLE_OPTIONAL +dnl Searches for an installed libtextstyle or uses the included source code +dnl parts that define only part of the API and does not do any styling. +dnl If found, it sets and AC_SUBSTs HAVE_LIBTEXTSTYLE=yes and the LIBTEXTSTYLE +dnl and LTLIBTEXTSTYLE variables, and augments the CPPFLAGS variable, and +dnl #defines HAVE_LIBTEXTSTYLE to 1. +dnl Otherwise, it sets and AC_SUBSTs HAVE_LIBTEXTSTYLE=no and LIBTEXTSTYLE and +dnl LTLIBTEXTSTYLE to empty. + +AC_DEFUN([gl_LIBTEXTSTYLE_OPTIONAL], +[ + AC_REQUIRE([gl_LIBTEXTSTYLE]) + if test $HAVE_LIBTEXTSTYLE = yes; then + TEXTSTYLE_H= + else + TEXTSTYLE_H=textstyle.h + AC_REQUIRE([AC_C_INLINE]) + AC_CHECK_FUNCS_ONCE([tcdrain]) + fi + AC_SUBST([TEXTSTYLE_H]) + AM_CONDITIONAL([GL_GENERATE_TEXTSTYLE_H], [test -n "$TEXTSTYLE_H"]) +]) diff --git a/modules/libtextstyle-optional b/modules/libtextstyle-optional new file mode 100644 index 0000000..f936986 --- /dev/null +++ b/modules/libtextstyle-optional @@ -0,0 +1,45 @@ +Description: +Try to use system libtextstyle for output of styled text. + +Files: +lib/textstyle.in.h +m4/libtextstyle-optional.m4 + +Depends-on: +libtextstyle +stdbool +unistd +fsync + +configure.ac: +gl_LIBTEXTSTYLE_OPTIONAL + +Makefile.am: +BUILT_SOURCES += $(TEXTSTYLE_H) + +# We need the following in order to create a dummy placeholder for +# <textstyle.h> when the system doesn't have one. +if GL_GENERATE_TEXTSTYLE_H +textstyle.h: textstyle.in.h $(top_builddir)/config.status + $(AM_V_GEN)rm -f $@-t $@ && \ + { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ + cat $(srcdir)/textstyle.in.h; \ + } > $@-t && \ + mv $@-t $@ +else +textstyle.h: $(top_builddir)/config.status + rm -f $@ +endif +MOSTLYCLEANFILES += textstyle.h textstyle.h-t + +Include: +#include <textstyle.h> + +Link: +$(LTLIBTEXTSTYLE) when linking with libtool, $(LIBTEXTSTYLE) otherwise + +License: +GPL + +Maintainer: +Bruno Haible, Akim Demaille -- 2.7.4
>From e4d8618dfd0c115f8b6076411e74d2df10e383af Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Wed, 20 Mar 2019 00:37:52 +0100 Subject: [PATCH 2/2] libtextstyle-optional: Add tests. * tests/test-libtextstyle.c: New file, based on libtextstyle's adhoc-tests/hello.c. * tests/test-libtextstyle-default.css: New file, copied from libtextstyle's adhoc-tests/hello-default.css. * modules/libtextstyle-optional-tests: New file. --- ChangeLog | 7 +++ modules/libtextstyle-optional-tests | 14 +++++ tests/test-libtextstyle-default.css | 7 +++ tests/test-libtextstyle.c | 101 ++++++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 modules/libtextstyle-optional-tests create mode 100644 tests/test-libtextstyle-default.css create mode 100644 tests/test-libtextstyle.c diff --git a/ChangeLog b/ChangeLog index af9d7f1..7f937aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2019-03-19 Bruno Haible <br...@clisp.org> + libtextstyle-optional: Add tests. + * tests/test-libtextstyle.c: New file, based on libtextstyle's + adhoc-tests/hello.c. + * tests/test-libtextstyle-default.css: New file, copied from + libtextstyle's adhoc-tests/hello-default.css. + * modules/libtextstyle-optional-tests: New file. + libtextstyle-optional: New module. * lib/textstyle.in.h: New file, based on libtextstyle's textstyle.h. * m4/libtextstyle-optional.m4: New file, based on m4/libtextstyle.m4. diff --git a/modules/libtextstyle-optional-tests b/modules/libtextstyle-optional-tests new file mode 100644 index 0000000..2722a18 --- /dev/null +++ b/modules/libtextstyle-optional-tests @@ -0,0 +1,14 @@ +Files: +tests/test-libtextstyle.c +tests/test-libtextstyle-default.css + +Depends-on: +isatty + +configure.ac: + +Makefile.am: +TESTS += test-libtextstyle +check_PROGRAMS += test-libtextstyle +test_libtextstyle_CPPFLAGS = $(AM_CPPFLAGS) -DSRCDIR=\"$(srcdir)/\" +test_libtextstyle_LDADD = $(LDADD) @LIBTEXTSTYLE@ diff --git a/tests/test-libtextstyle-default.css b/tests/test-libtextstyle-default.css new file mode 100644 index 0000000..7eba906 --- /dev/null +++ b/tests/test-libtextstyle-default.css @@ -0,0 +1,7 @@ +/* This file is in the public domain. + + Styling rules for the color-hello example. */ + +.name { text-decoration : underline; } +.boy-name { background-color : rgb(123,201,249); } +.girl-name { background-color : rgb(250,149,158); } diff --git a/tests/test-libtextstyle.c b/tests/test-libtextstyle.c new file mode 100644 index 0000000..970713f --- /dev/null +++ b/tests/test-libtextstyle.c @@ -0,0 +1,101 @@ +/* Ad-hoc testing program for GNU libtextstyle. + Copyright (C) 2018-2019 Free Software Foundation, Inc. + Written by Bruno Haible <br...@clisp.org>, 2018. + + 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 <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <textstyle.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +int +main (int argc, char *argv[]) +{ + const char *program_name = argv[0]; + int i; + + /* Parse the command-line arguments. */ + for (i = 1; i < argc; i++) + { + const char *arg = argv[i]; + if (strncmp (arg, "--color=", 8) == 0) + handle_color_option (arg + 8); + else if (strncmp (arg, "--style=", 8) == 0) + handle_style_option (arg + 8); + else if (arg[0] == '-') + { + fprintf (stderr, "%s: invalid argument: %s\n", program_name, arg); + exit (1); + } + else + /* Handle non-option arguments here. */ + ; + } + + /* Handle the --color=test special argument. */ + if (color_test_mode) + { + print_color_test (); + exit (0); + } + + #if HAVE_LIBTEXTSTYLE + if (color_mode == color_yes + || (color_mode == color_tty && isatty (STDOUT_FILENO)) + || color_mode == color_html) + { + /* If no style file is explicitly specified, use the default in the + source directory. */ + if (style_file_name == NULL) + style_file_name = SRCDIR "test-libtextstyle-default.css"; + } + else + /* No styling. */ + style_file_name = NULL; + #endif + + /* Create a terminal output stream that uses this style file. */ + styled_ostream_t stream = + (color_mode == color_html + ? html_styled_ostream_create (file_ostream_create (stdout), + style_file_name) + : styled_ostream_create (STDOUT_FILENO, "(stdout)", TTYCTL_AUTO, + style_file_name)); + + ostream_write_str (stream, "Hello "); + + /* Associate the entire full name in CSS class 'name'. */ + styled_ostream_begin_use_class (stream, "name"); + + ostream_write_str (stream, "Dr. "); + styled_ostream_begin_use_class (stream, "boy-name"); + ostream_write_str (stream, "Linus"); + styled_ostream_end_use_class (stream, "boy-name"); + ostream_write_str (stream, " Pauling"); + + /* Terminate the name. */ + styled_ostream_end_use_class (stream, "name"); + + ostream_write_str (stream, "!\n"); + + /* Flush and close the terminal stream. */ + styled_ostream_free (stream); + + return 0; +} -- 2.7.4