root/src/libsir/src/sirtextstyle.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _sir_gettextstyle
  2. _sir_settextstyle
  3. _sir_getdefstyle
  4. _sir_resettextstyles
  5. _sir_formatstyle
  6. _sir_validtextstyle
  7. _sir_setcolormode
  8. _sir_settextstyle
  9. _sir_gettextstyle
  10. _sir_getdefstyle
  11. _sir_resettextstyles
  12. _sir_formatstyle
  13. _sir_validtextstyle
  14. _sir_setcolormode

   1 /*
   2  * sirtextstyle.c
   3  *
   4  * Version: 2.2.5
   5  *
   6  * -----------------------------------------------------------------------------
   7  *
   8  * SPDX-License-Identifier: MIT
   9  *
  10  * Copyright (c) 2018-2024 Ryan M. Lederman <lederman@gmail.com>
  11  *
  12  * Permission is hereby granted, free of charge, to any person obtaining a copy of
  13  * this software and associated documentation files (the "Software"), to deal in
  14  * the Software without restriction, including without limitation the rights to
  15  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  16  * the Software, and to permit persons to whom the Software is furnished to do so,
  17  * subject to the following conditions:
  18  *
  19  * The above copyright notice and this permission notice shall be included in all
  20  * copies or substantial portions of the Software.
  21  *
  22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  24  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  25  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  26  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28  *
  29  * -----------------------------------------------------------------------------
  30  */
  31 
  32 #include "sir/textstyle.h"
  33 #include "sir/internal.h"
  34 #include "sir/defaults.h"
  35 
  36 #if !defined(SIR_NO_TEXT_STYLING)
  37 static sir_colormode sir_color_mode = SIRCM_16;
  38 
  39 /**
  40  * Wrapper around the level-to-style map and the color mode. This is the data
  41  * structure protected by the SIRMI_TEXTSTYLE mutex. */
  42 sir_text_style_data sir_text_style_section = {
  43     &sir_level_to_style_map[0],
  44     &sir_color_mode
  45 };
  46 
  47 const char* _sir_gettextstyle(sir_level level) {
     /* [previous][next][first][last][top][bottom][index][help] */
  48     static const size_t low  = 0;
  49     static const size_t high = SIR_NUMLEVELS - 1;
  50 
  51     _SIR_LOCK_SECTION(sir_text_style_data, data, SIRMI_TEXTSTYLE, NULL);
  52     const char* retval = SIR_UNKNOWN;
  53 
  54     _SIR_DECLARE_BIN_SEARCH(low, high);
  55     _SIR_BEGIN_BIN_SEARCH()
  56 
  57     if (data->map[_mid].level == level) {
  58         retval = data->map[_mid].str;
  59         break;
  60     }
  61 
  62     _SIR_ITERATE_BIN_SEARCH((data->map[_mid].level < level ? 1 : -1));
  63     _SIR_END_BIN_SEARCH();
  64     _SIR_UNLOCK_SECTION(SIRMI_TEXTSTYLE);
  65 
  66     return retval;
  67 }
  68 
  69 bool _sir_settextstyle(sir_level level, const sir_textstyle* style) {
     /* [previous][next][first][last][top][bottom][index][help] */
  70     (void)_sir_seterror(_SIR_E_NOERROR);
  71 
  72     if (!_sir_sanity() || !_sir_validlevel(level))
  73         return false;
  74 
  75     _SIR_LOCK_SECTION(sir_text_style_data, data, SIRMI_TEXTSTYLE, false);
  76     bool updated              = false;
  77     static const size_t low   = 0;
  78     static const size_t high  = SIR_NUMLEVELS - 1;
  79 
  80     _SIR_DECLARE_BIN_SEARCH(low, high);
  81     _SIR_BEGIN_BIN_SEARCH()
  82 
  83     if (data->map[_mid].level == level) {
  84         (void)memcpy(&data->map[_mid].style, style, sizeof(sir_textstyle));
  85         updated = _sir_formatstyle(*data->color_mode, style, data->map[_mid].str);
  86         break;
  87     }
  88 
  89     _SIR_ITERATE_BIN_SEARCH((data->map[_mid].level < level ? 1 : -1));
  90     _SIR_END_BIN_SEARCH();
  91     _SIR_UNLOCK_SECTION(SIRMI_TEXTSTYLE);
  92 
  93     SIR_ASSERT(updated);
  94     return updated;
  95 }
  96 
  97 const sir_textstyle* _sir_getdefstyle(sir_level level) {
     /* [previous][next][first][last][top][bottom][index][help] */
  98     switch (level) {
  99         case SIRL_EMERG:  return &sir_lvl_emerg_def_style;
 100         case SIRL_ALERT:  return &sir_lvl_alert_def_style;
 101         case SIRL_CRIT:   return &sir_lvl_crit_def_style;
 102         case SIRL_ERROR:  return &sir_lvl_error_def_style;
 103         case SIRL_WARN:   return &sir_lvl_warn_def_style;
 104         case SIRL_NOTICE: return &sir_lvl_notice_def_style;
 105         case SIRL_INFO:   return &sir_lvl_info_def_style;
 106         case SIRL_DEBUG:  return &sir_lvl_debug_def_style;
 107         // GCOVR_EXCL_START
 108         default: /* this should never happen */
 109             SIR_ASSERT(level);
 110             return &sir_lvl_info_def_style;
 111         // GCOVR_EXCL_STOP
 112     }
 113 }
 114 
 115 bool _sir_resettextstyles(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 116     (void)_sir_seterror(_SIR_E_NOERROR);
 117 
 118     if (!_sir_sanity())
 119         return false;
 120 
 121     _SIR_LOCK_SECTION(sir_text_style_data, data, SIRMI_TEXTSTYLE, false);
 122     bool all_ok = true;
 123     for (size_t n = 0; n < SIR_NUMLEVELS; n++) {
 124         (void)memcpy(&data->map[n].style, _sir_getdefstyle(data->map[n].level),
 125              sizeof(sir_textstyle));
 126         _sir_eqland(all_ok, _sir_formatstyle(*data->color_mode, &data->map[n].style,
 127             data->map[n].str));
 128     }
 129 
 130     _SIR_UNLOCK_SECTION(SIRMI_TEXTSTYLE);
 131     return all_ok;
 132 }
 133 
 134 bool _sir_formatstyle(sir_colormode mode, const sir_textstyle* style,
     /* [previous][next][first][last][top][bottom][index][help] */
 135     char buf[SIR_MAXSTYLE]) {
 136     if (!_sir_validtextstyle(mode, style))
 137         return false;
 138 
 139     _sir_resetstr(buf);
 140 
 141     switch (mode) {
 142         case SIRCM_16:
 143             /* \x1b[attr;fg;bgm */
 144             return 0 < snprintf(buf, SIR_MAXSTYLE, "%s%"PRIu8";%"PRIu8";%"PRIu8"m",
 145                 SIR_ESC, (uint8_t)style->attr, (uint8_t)_sir_mkansifgcolor(style->fg),
 146                 (uint8_t)_sir_mkansibgcolor(style->bg));
 147         case SIRCM_256: {
 148             /* \x1b[attr;38;5;fg;48;5;bgm */
 149             return 0 < snprintf(buf, SIR_MAXSTYLE,
 150                 "%s%"PRIu8";%"PRIu8";5;%"PRIu8";%"PRIu8";5;%"PRIu8"m", SIR_ESC,
 151                 (uint8_t)style->attr, (uint8_t)_sir_getansifgcmd(style->fg),
 152                 (uint8_t)style->fg, (uint8_t)_sir_getansibgcmd(style->bg),
 153                 (uint8_t)style->bg);
 154         }
 155         case SIRCM_RGB: {
 156             /* \x1b[attr;38;2;rrr;ggg;bbb;48;2;rrr;ggg;bbbm */
 157             return 0 < snprintf(buf, SIR_MAXSTYLE,
 158                 "%s%"PRIu8";%"PRIu8";2;%"PRIu8";%"PRIu8";%"PRIu8";%"PRIu8
 159                 ";2;%"PRIu8";%"PRIu8";%"PRIu8"m", SIR_ESC, (uint8_t)style->attr,
 160                 (uint8_t)_sir_getansifgcmd(style->fg), _sir_getredfromcolor(style->fg),
 161                 _sir_getgreenfromcolor(style->fg), _sir_getbluefromcolor(style->fg),
 162                 (uint8_t)_sir_getansibgcmd(style->bg), _sir_getredfromcolor(style->bg),
 163                 _sir_getgreenfromcolor(style->bg), _sir_getbluefromcolor(style->bg));
 164         }
 165         case SIRCM_INVALID: // GCOVR_EXCL_START
 166         default:
 167             return false;
 168     } // GCOVR_EXCL_STOP
 169 }
 170 
 171 bool _sir_validtextstyle(sir_colormode mode, const sir_textstyle* style) {
     /* [previous][next][first][last][top][bottom][index][help] */
 172     if (!_sir_validptr(style) || !_sir_validcolormode(mode))
 173         return false;
 174 
 175     sir_textcolor fg = SIRCM_16 == mode ? _sir_mkansifgcolor(style->fg) : style->fg;
 176     sir_textcolor bg = SIRCM_16 == mode ? _sir_mkansibgcolor(style->bg) : style->bg;
 177 
 178     if (!_sir_validtextattr(style->attr) || !_sir_validtextcolor(mode, fg) ||
 179         !_sir_validtextcolor(mode, bg))
 180         return false;
 181 
 182     if (SIRTC_DEFAULT != style->fg && SIRTC_DEFAULT != style->bg &&
 183         style->fg == style->bg) {
 184         _sir_selflog("error: fg color %08"PRIx32" and bg color %08"PRIx32
 185                      " are identical; text would be invisible", style->fg,
 186                      style->bg);
 187         SIR_ASSERT(SIRTC_DEFAULT != style->fg && SIRTC_DEFAULT != style->bg &&
 188                 style->fg == style->bg);
 189         return _sir_seterror(_SIR_E_TEXTSTYLE);
 190     }
 191 
 192     return true;
 193 }
 194 
 195 bool _sir_setcolormode(sir_colormode mode) {
     /* [previous][next][first][last][top][bottom][index][help] */
 196     if (!_sir_validcolormode(mode))
 197         return false;
 198 
 199     _SIR_LOCK_SECTION(sir_text_style_data, data, SIRMI_TEXTSTYLE, false);
 200     if (*data->color_mode != mode) {
 201         sir_colormode old = *data->color_mode;
 202         *data->color_mode = mode;
 203         _sir_selflog("color mode changed from %"PRId32" to %"PRId32, old, mode);
 204 
 205         /* when the color mode changes, it's necessary to regenerate the text styles
 206          * we're holding. for example in the case of downgrading color modes, the
 207          * styles in memory could be incompatible with the new mode. */
 208         if (!_sir_resettextstyles()) {
 209             _sir_selflog("error: failed to reset text styles!");
 210             _SIR_UNLOCK_SECTION(SIRMI_TEXTSTYLE);
 211             return false;
 212         }
 213     } else {
 214         _sir_selflog("skipped superfluous update of color mode: %"PRId32, mode);
 215     }
 216     _SIR_UNLOCK_SECTION(SIRMI_TEXTSTYLE);
 217 
 218     return true;
 219 }
 220 #else /* SIR_NO_TEXT_STYLING */
 221 bool _sir_settextstyle(sir_level level, const sir_textstyle* style) {
     /* [previous][next][first][last][top][bottom][index][help] */
 222     SIR_UNUSED(level);
 223     SIR_UNUSED(style);
 224     return false;
 225 }
 226 
 227 const char* _sir_gettextstyle(sir_level level) { // GCOVR_EXCL_START
     /* [previous][next][first][last][top][bottom][index][help] */
 228     SIR_UNUSED(level);
 229     SIR_ASSERT(false);
 230     return NULL;
 231 }
 232 
 233 const sir_textstyle* _sir_getdefstyle(sir_level level) {
     /* [previous][next][first][last][top][bottom][index][help] */
 234     SIR_UNUSED(level);
 235     SIR_ASSERT(false);
 236     return NULL;
 237 }
 238 
 239 bool _sir_resettextstyles(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 240     return false;
 241 }
 242 
 243 bool _sir_formatstyle(sir_colormode mode, const sir_textstyle* style,
     /* [previous][next][first][last][top][bottom][index][help] */
 244     char buf[SIR_MAXSTYLE]) {
 245     SIR_UNUSED(mode);
 246     SIR_UNUSED(style);
 247     SIR_UNUSED(buf);
 248     return false;
 249 }
 250 
 251 bool _sir_validtextstyle(sir_colormode mode, const sir_textstyle* style) {
     /* [previous][next][first][last][top][bottom][index][help] */
 252     SIR_UNUSED(mode);
 253     SIR_UNUSED(style);
 254     return false;
 255 }
 256 
 257 bool _sir_setcolormode(sir_colormode mode) {
     /* [previous][next][first][last][top][bottom][index][help] */
 258     SIR_UNUSED(mode);
 259     return false;
 260 } // GCOVR_EXCL_STOP
 261 #endif

/* [previous][next][first][last][top][bottom][index][help] */