/* Simple test program for the term-style-control module. Copyright (C) 2019-2023 Free Software Foundation, Inc. Written by Bruno Haible , 2019. 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 /* Specification. */ #include "term-style-control.h" #include #include #include #include "full-write.h" /* This program outputs the line: Hello Dr. Linus Pauling! with underlining here: _________________ and a cyan background color here: _____ */ /* ECMA-48 / ISO 6429 escape sequences. See https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters */ static const char set_underline_on[] = "\033[4m"; static const char set_underline_off[] = "\033[24m"; static const char set_background_color_cyan[] = "\033[46m"; static const char set_background_color_default[] = "\033[49m"; struct term_style_user_data { /* These fields are marked volatile, because they are accessed from the async-safe function async_set_attributes_from_default. */ bool volatile underline; bool volatile background_color_cyan; struct term_style_control_data ctrl_data; }; static struct term_style_control_data * get_control_data (struct term_style_user_data *user_data) { return &user_data->ctrl_data; } static void restore (struct term_style_user_data *user_data) { fputs (set_underline_off, stdout); fputs (set_background_color_default, stdout); fflush (stdout); } static _GL_ASYNC_SAFE void async_restore (struct term_style_user_data *user_data) { /* No calls here! */ full_write (STDOUT_FILENO, set_underline_off, strlen (set_underline_off)); full_write (STDOUT_FILENO, set_background_color_default, strlen (set_background_color_default)); } static _GL_ASYNC_SAFE void async_set_attributes_from_default (struct term_style_user_data *user_data) { /* No calls here! */ if (user_data->underline) full_write (STDOUT_FILENO, set_underline_on, strlen (set_underline_on)); if (user_data->background_color_cyan) full_write (STDOUT_FILENO, set_background_color_cyan, strlen (set_background_color_cyan)); } static const struct term_style_controller controller = { get_control_data, restore, async_restore, async_set_attributes_from_default }; int main (int argc, char *argv[]) { struct term_style_user_data user_data; /* Initialization. */ user_data.underline = false; user_data.background_color_cyan = false; activate_term_style_controller (&controller, &user_data, STDOUT_FILENO, TTYCTL_AUTO); /* As long as no styling is needed, we can stay in the default mode. */ fputs ("Hello ", stdout); fflush (stdout); /* Before any styling, enable the non-default mode. */ activate_term_non_default_mode (&controller, &user_data); /* Set user_data.underline *before* emitting the appropriate escape sequences, otherwise async_set_attributes_from_default will not do its job correctly. */ user_data.underline = true; fputs (set_underline_on, stdout); fflush (stdout); fputs ("Dr. ", stdout); fflush (stdout); /* Set user_data.background_color_cyan *before* emitting the appropriate escape sequences, otherwise async_set_attributes_from_default will not do its job correctly. */ user_data.background_color_cyan = true; fputs (set_background_color_cyan, stdout); fflush (stdout); fputs ("Linus", stdout); fflush (stdout); user_data.background_color_cyan = false; fputs (set_background_color_default, stdout); fflush (stdout); fputs (" Pauling", stdout); fflush (stdout); user_data.underline = false; fputs (set_underline_off, stdout); fflush (stdout); /* Needed as a prerequisite of the deactivate_term_style_controller call below. */ deactivate_term_non_default_mode (&controller, &user_data); fputs ("!\n", stdout); /* If the user_data was allocated in heap memory, with indefinite extent, this call would be optional. But since we have allocated it on the stack, we must deactivate it before it goes out of scope. Otherwise we get undefined behaviour in an atexit() handler. */ deactivate_term_style_controller (&controller, &user_data); return 0; }