LCOV - code coverage report
Current view: top level - snaplogger - convert_ansi.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 572 572
Test Date: 2025-07-26 11:53:05 Functions: 100.0 % 20 20
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2013-2025  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/snaplogger
       4              : // contact@m2osw.com
       5              : //
       6              : // This program is free software; you can redistribute it and/or modify
       7              : // it under the terms of the GNU General Public License as published by
       8              : // the Free Software Foundation; either version 2 of the License, or
       9              : // (at your option) any later version.
      10              : //
      11              : // This program is distributed in the hope that it will be useful,
      12              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : // GNU General Public License for more details.
      15              : //
      16              : // You should have received a copy of the GNU General Public License along
      17              : // with this program; if not, write to the Free Software Foundation, Inc.,
      18              : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19              : 
      20              : /** \file
      21              :  * \brief Implementation of the ANSI converter.
      22              :  *
      23              :  * This file implements a class that takes output from a console and
      24              :  * convert it in various ways such as HTML, markdown, or plain text.
      25              :  */
      26              : 
      27              : // self
      28              : //
      29              : #include    "snaplogger/exception.h"
      30              : #include    "snaplogger/convert_ansi.h"
      31              : 
      32              : 
      33              : // libutf8
      34              : //
      35              : #include    <libutf8/base.h>
      36              : #include    <libutf8/iterator.h>
      37              : #include    <libutf8/libutf8.h>
      38              : 
      39              : 
      40              : // snapdev
      41              : //
      42              : #include    <snapdev/hexadecimal_string.h>
      43              : #include    <snapdev/join_strings.h>
      44              : 
      45              : 
      46              : // C++
      47              : //
      48              : #include    <iostream>
      49              : 
      50              : 
      51              : // last include
      52              : //
      53              : #include    <snapdev/poison.h>
      54              : 
      55              : 
      56              : 
      57              : namespace snaplogger
      58              : {
      59              : 
      60              : 
      61              : namespace
      62              : {
      63              : 
      64              : 
      65              : constexpr char32_t const        ESCAPE = U'\x1B';    // Escape code
      66              : 
      67              : constexpr std::uint32_t const   g_colors[] =
      68              : {
      69              :     0x000000, 0xde382b, 0x39b54a, 0xffc706, 0x006fb8, 0x762671, 0x2cb5e9, 0xcccccc,
      70              :     0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff,
      71              :     0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
      72              :     0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af,
      73              :     0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff,
      74              :     0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f,
      75              :     0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af,
      76              :     0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff,
      77              :     0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f,
      78              :     0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af,
      79              :     0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff,
      80              :     0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f,
      81              :     0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af,
      82              :     0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff,
      83              :     0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f,
      84              :     0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af,
      85              :     0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff,
      86              :     0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f,
      87              :     0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787, 0xafd7af,
      88              :     0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff,
      89              :     0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f,
      90              :     0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af,
      91              :     0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff,
      92              :     0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f,
      93              :     0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af,
      94              :     0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff,
      95              :     0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f,
      96              :     0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, 0xffd75f, 0xffd787, 0xffd7af,
      97              :     0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff,
      98              :     0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e,
      99              :     0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e,
     100              :     0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee,
     101              : };
     102              : 
     103              : 
     104              : 
     105              : }
     106              : // no name namespace
     107              : 
     108              : 
     109              : 
     110              : 
     111      1112369 : convert_ansi::convert_ansi(ansi_output_t type)
     112      1112369 :     : f_type(type)
     113              : {
     114      1112369 : }
     115              : 
     116              : 
     117            3 : ansi_output_t convert_ansi::get_type() const
     118              : {
     119            3 :     return f_type;
     120              : }
     121              : 
     122              : 
     123          315 : void convert_ansi::set_optimize(bool optimize)
     124              : {
     125          315 :     f_optimize = optimize;
     126          315 : }
     127              : 
     128              : 
     129          318 : bool convert_ansi::get_optimize() const
     130              : {
     131          318 :     return f_optimize;
     132              : }
     133              : 
     134              : 
     135          210 : void convert_ansi::set_br(bool br)
     136              : {
     137          210 :     f_br = br;
     138          210 : }
     139              : 
     140              : 
     141          213 : bool convert_ansi::get_br() const
     142              : {
     143          213 :     return f_br;
     144              : }
     145              : 
     146              : 
     147      1112891 : void convert_ansi::write(std::string const & in)
     148              : {
     149      1112891 :     f_data.push_back(in);
     150      1112891 : }
     151              : 
     152              : 
     153      1112891 : std::string convert_ansi::read()
     154              : {
     155              :     // we assume that on a following up call you have brand new data
     156              :     // so we need to make sure the state was properly reset
     157              :     //
     158      1112891 :     f_graphical_state = GRAPHICAL_STATE_NORMAL;
     159      1112891 :     f_graphical_state_for_styles = GRAPHICAL_STATE_NORMAL;
     160      1112891 :     f_current_graphical_state = GRAPHICAL_STATE_NORMAL;
     161      1112891 :     f_result.clear();
     162              :     //f_param_pos = 0;
     163      1112891 :     f_state = state_t::ANSI_STATE_PLAIN_TEXT;
     164      1112891 :     f_conceal = false;
     165      1112891 :     f_span_open = false;
     166      1112891 :     f_invalid_input = false;
     167              : 
     168      1112891 :     char32_t last(U'\0');
     169              :     for(;;)
     170              :     {
     171      7816677 :         char32_t wc(last);
     172      7816677 :         if(wc == U'\0')
     173              :         {
     174      7816669 :             wc = getc();
     175              :         }
     176              :         else
     177              :         {
     178            8 :             last = U'\0';
     179              :         }
     180      7816677 :         if(wc == U'\r')
     181              :         {
     182           15 :             wc = getc();
     183           15 :             if(wc != U'\n')
     184              :             {
     185            8 :                 last = wc;
     186            8 :                 wc = U'\n';
     187              :             }
     188              :         }
     189      7816677 :         if(wc == libutf8::EOS)
     190              :         {
     191      1112891 :             break;
     192              :         }
     193              : 
     194      6703786 :         switch(f_state)
     195              :         {
     196      1134242 :         case state_t::ANSI_STATE_PLAIN_TEXT:
     197      1134242 :             if(wc == ESCAPE)
     198              :             {
     199      1114229 :                 f_state = state_t::ANSI_STATE_ESCAPE;
     200              :             }
     201        20013 :             else if(wc != U'\0' && !f_conceal)
     202              :             {
     203        19838 :                 switch(f_type)
     204              :                 {
     205        13405 :                 case ansi_output_t::ANSI_OUTPUT_HTML:
     206        13405 :                     if(!iswspace(wc))
     207              :                     {
     208        11680 :                         start_style();
     209              :                     }
     210        13405 :                     switch(wc)
     211              :                     {
     212            5 :                     case U'"':
     213            5 :                         f_result += "&quot;";
     214            5 :                         break;
     215              : 
     216            5 :                     case U'&':
     217            5 :                         f_result += "&amp;";
     218            5 :                         break;
     219              : 
     220            5 :                     case U'\'':
     221            5 :                         f_result += "&apos;";
     222            5 :                         break;
     223              : 
     224           10 :                     case U'<':
     225           10 :                         f_result += "&lt;";
     226           10 :                         break;
     227              : 
     228           10 :                     case U'>': // important for xhtml
     229           10 :                         f_result += "&gt;";
     230           10 :                         break;
     231              : 
     232           15 :                     case U'\n':
     233           15 :                         if(f_br)
     234              :                         {
     235           12 :                             f_result += "<br/>";
     236              :                         }
     237           15 :                         f_result += '\n';
     238           15 :                         break;
     239              : 
     240        13355 :                     default:
     241        13355 :                         f_result += libutf8::to_u8string(wc);
     242        13355 :                         break;
     243              : 
     244              :                     }
     245        13405 :                     break;
     246              : 
     247         2681 :                 case ansi_output_t::ANSI_OUTPUT_MARKDOWN:
     248         2681 :                     if(iswspace(wc))
     249              :                     {
     250          345 :                         if(f_graphical_state != f_current_graphical_state
     251           60 :                         && f_current_graphical_state != GRAPHICAL_STATE_NORMAL)
     252              :                         {
     253           60 :                             end_style();
     254           60 :                             f_current_graphical_state = GRAPHICAL_STATE_NORMAL;
     255              :                         }
     256              :                     }
     257              :                     else
     258              :                     {
     259         2336 :                         start_style();
     260              :                     }
     261         2681 :                     switch(wc)
     262              :                     {
     263           16 :                     case U'*':
     264              :                     case U'-':
     265              :                     case U'#':
     266              :                     case U'_':
     267              :                     case U'<':
     268              :                     case U'>':
     269              :                     case U'`':
     270              :                     case U'[':
     271              :                     case U'\\':
     272           16 :                         f_result += '\\';
     273           16 :                         f_result += static_cast<char>(wc);
     274           16 :                         break;
     275              : 
     276            3 :                     case U'\n':
     277            3 :                         end_style();
     278            3 :                         f_current_graphical_state = GRAPHICAL_STATE_NORMAL;
     279            3 :                         f_result += '\n';
     280            3 :                         break;
     281              : 
     282         2662 :                     default:
     283         2662 :                         f_result += libutf8::to_u8string(wc);
     284         2662 :                         break;
     285              : 
     286              :                     }
     287         2681 :                     break;
     288              : 
     289         3752 :                 case ansi_output_t::ANSI_OUTPUT_PLAIN_TEXT:
     290         3752 :                     f_result += libutf8::to_u8string(wc);
     291         3752 :                     break;
     292              : 
     293              :                 }
     294              :             }
     295      1134242 :             break;
     296              : 
     297      1114229 :         case state_t::ANSI_STATE_ESCAPE:
     298      1114229 :             if(wc == U'[')
     299              :             {
     300              :                 // Escape + '[' = Control Sequence Introducer
     301              :                 //
     302      1114222 :                 f_state = state_t::ANSI_STATE_PARAMETERS;
     303      1114222 :                 f_parameters.push_back(0);
     304              :             }
     305              :             else
     306              :             {
     307              :                 // we lose the Escape in case of an invalid CSI start
     308              :                 //
     309            7 :                 f_result += libutf8::to_u8string(wc);
     310              : 
     311            7 :                 f_state = state_t::ANSI_STATE_PLAIN_TEXT;
     312              :             }
     313      1114229 :             break;
     314              : 
     315      4455315 :         case state_t::ANSI_STATE_PARAMETERS:
     316      4455315 :             if(wc >= U'@' && wc <= U'\x7E')
     317              :             {
     318              :                 // ends the sequence and process it
     319              :                 //
     320      1114222 :                 switch(wc)
     321              :                 {
     322      1114046 :                 case U'm':
     323      1114046 :                     apply_graphical_rendition();
     324      1114046 :                     break;
     325              : 
     326          133 :                 case U'A':
     327              :                 case U'B':
     328              :                 case U'C':
     329              :                 case U'D':
     330              :                 case U'E':
     331              :                 case U'F':
     332              :                 case U'G':
     333              :                 case U'H':
     334              :                 case U'J':
     335              :                 case U'K':
     336              :                 case U'S':
     337              :                 case U'T':
     338              :                 case U'f':
     339              :                 case U'h':
     340              :                 case U'i':
     341              :                 case U'l':
     342              :                 case U'n':
     343              :                 case U's':
     344              :                 case U'u':
     345              :                     // valid but ignored
     346          133 :                     break;
     347              : 
     348           43 :                 default:
     349              :                     // this is not really invalid, just unsupported
     350              :                     //
     351           43 :                     f_invalid_input = true;
     352           43 :                     break;
     353              : 
     354              :                 }
     355              : 
     356      1114222 :                 f_parameters.clear();
     357              : 
     358      1114222 :                 f_state = state_t::ANSI_STATE_PLAIN_TEXT;
     359              :             }
     360      3341093 :             else if(wc >= U'0' && wc <= U'9')
     361              :             {
     362      2228446 :                 f_parameters[f_parameters.size() - 1] *= 10;
     363      2228446 :                 f_parameters[f_parameters.size() - 1] += wc - U'0';
     364              :             }
     365              :             else 
     366              :             {
     367              :                 // we expect ';' or ':' here because all the sequences we
     368              :                 // support are expected to have such as the separator
     369              :                 // (the ':' is at times used for color definitions)
     370              :                 //
     371      1112647 :                 if(wc != U';'
     372      1111988 :                 && wc != U':')
     373              :                 {
     374              :                     // "invalid" is not automatically true, but we do not
     375              :                     // recognize other sequences at the moment
     376              :                     //
     377      1111988 :                     f_invalid_input = true;
     378              :                 }
     379      1112647 :                 f_parameters.push_back(0);
     380              :             }
     381      4455315 :             break;
     382              : 
     383              :         }
     384      6703786 :     }
     385              : 
     386      1112891 :     end_style();
     387              : 
     388      1112891 :     return f_result;
     389              : }
     390              : 
     391              : 
     392      1114046 : void convert_ansi::apply_graphical_rendition()
     393              : {
     394      3340346 :     for(f_param_pos = 0; static_cast<std::size_t>(f_param_pos) < f_parameters.size();)
     395              :     {
     396              : //std::cerr << "\n--- PARAMS! switch: " << f_parameters[f_param_pos] << "\n";
     397      2226300 :         switch(f_parameters[f_param_pos])
     398              :         {
     399          680 :         case 0:
     400          680 :             update_style(GRAPHICAL_STATE_NORMAL, GRAPHICAL_STATE_ALL);
     401          680 :             ++f_param_pos;
     402          680 :             f_conceal = false;
     403          680 :             break;
     404              : 
     405           14 :         case 1:
     406           14 :             update_style(GRAPHICAL_STATE_BOLD, GRAPHICAL_STATE_LIGHT);
     407           14 :             ++f_param_pos;
     408           14 :             break;
     409              : 
     410      1112002 :         case 2:
     411      1112002 :             update_style(GRAPHICAL_STATE_LIGHT, GRAPHICAL_STATE_BOLD);
     412      1112002 :             ++f_param_pos;
     413      1112002 :             break;
     414              : 
     415      1112002 :         case 3:
     416      1112002 :             update_style(GRAPHICAL_STATE_ITALIC);
     417      1112002 :             ++f_param_pos;
     418      1112002 :             break;
     419              : 
     420           92 :         case 4:
     421           92 :             update_style(GRAPHICAL_STATE_UNDERLINE, GRAPHICAL_STATE_DOUBLE_UNDERLINE);
     422           92 :             ++f_param_pos;
     423           92 :             break;
     424              : 
     425           14 :         case 5:
     426           14 :             update_style(GRAPHICAL_STATE_SLOW_BLINK, GRAPHICAL_STATE_FAST_BLINK);
     427           14 :             ++f_param_pos;
     428           14 :             break;
     429              : 
     430           14 :         case 6:
     431           14 :             update_style(GRAPHICAL_STATE_FAST_BLINK, GRAPHICAL_STATE_SLOW_BLINK);
     432           14 :             ++f_param_pos;
     433           14 :             break;
     434              : 
     435           21 :         case 7:
     436           21 :             update_style(GRAPHICAL_STATE_INVERSE);
     437           21 :             ++f_param_pos;
     438           21 :             break;
     439              : 
     440           14 :         case 8:
     441           14 :             f_conceal = true;
     442           14 :             ++f_param_pos;
     443           14 :             break;
     444              : 
     445          140 :         case 9:
     446          140 :             update_style(GRAPHICAL_STATE_CROSS_OUT);
     447          140 :             ++f_param_pos;
     448          140 :             break;
     449              : 
     450           84 :         case 21:
     451           84 :             update_style(GRAPHICAL_STATE_DOUBLE_UNDERLINE, GRAPHICAL_STATE_UNDERLINE);
     452           84 :             ++f_param_pos;
     453           84 :             break;
     454              : 
     455           14 :         case 22:
     456           14 :             update_style(0, GRAPHICAL_STATE_BOLD | GRAPHICAL_STATE_LIGHT);
     457           14 :             ++f_param_pos;
     458           14 :             break;
     459              : 
     460            7 :         case 23:
     461            7 :             update_style(0, GRAPHICAL_STATE_ITALIC);
     462            7 :             ++f_param_pos;
     463            7 :             break;
     464              : 
     465           14 :         case 24:
     466           14 :             update_style(0, GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_DOUBLE_UNDERLINE);
     467           14 :             ++f_param_pos;
     468           14 :             break;
     469              : 
     470           14 :         case 25:
     471           14 :             update_style(0, GRAPHICAL_STATE_SLOW_BLINK | GRAPHICAL_STATE_FAST_BLINK);
     472           14 :             ++f_param_pos;
     473           14 :             break;
     474              : 
     475            7 :         case 26:
     476            7 :             update_style(GRAPHICAL_STATE_PROPORTIONAL);
     477            7 :             ++f_param_pos;
     478            7 :             break;
     479              : 
     480            7 :         case 27:
     481            7 :             update_style(0, GRAPHICAL_STATE_INVERSE);
     482            7 :             ++f_param_pos;
     483            7 :             break;
     484              : 
     485            7 :         case 28:
     486            7 :             f_conceal = false;
     487            7 :             ++f_param_pos;
     488            7 :             break;
     489              : 
     490            7 :         case 29:
     491            7 :             update_style(0, GRAPHICAL_STATE_CROSS_OUT);
     492            7 :             ++f_param_pos;
     493            7 :             break;
     494              : 
     495           56 :         case 30:
     496              :         case 31:
     497              :         case 32:
     498              :         case 33:
     499              :         case 34:
     500              :         case 35:
     501              :         case 36:
     502              :         case 37:
     503              :             // the first 8 colors are the "standard" CSI colors
     504              :             //
     505           56 :             f_foreground_color = g_colors[f_parameters[f_param_pos] - 30];
     506           56 :             update_style(GRAPHICAL_STATE_FOREGROUND_COLOR);
     507           56 :             ++f_param_pos;
     508           56 :             break;
     509              : 
     510           57 :         case 38:
     511           57 :             f_foreground_color = get_color(true);
     512           57 :             update_style(GRAPHICAL_STATE_FOREGROUND_COLOR);
     513           57 :             break;
     514              : 
     515          161 :         case 39:
     516          161 :             f_foreground_color = 0;
     517          161 :             update_style(0, GRAPHICAL_STATE_FOREGROUND_COLOR);
     518          161 :             ++f_param_pos;
     519          161 :             break;
     520              : 
     521           56 :         case 40:
     522              :         case 41:
     523              :         case 42:
     524              :         case 43:
     525              :         case 44:
     526              :         case 45:
     527              :         case 46:
     528              :         case 47:
     529              :             // the first 8 colors are the "standard" CSI colors
     530              :             //
     531           56 :             f_background_color = g_colors[f_parameters[f_param_pos] - 40];
     532           56 :             update_style(GRAPHICAL_STATE_BACKGROUND_COLOR);
     533           56 :             ++f_param_pos;
     534           56 :             break;
     535              : 
     536           44 :         case 48:
     537           44 :             f_background_color = get_color(false);
     538           44 :             update_style(GRAPHICAL_STATE_BACKGROUND_COLOR);
     539           44 :             break;
     540              : 
     541          147 :         case 49:
     542          147 :             f_background_color = 0;
     543          147 :             update_style(0, GRAPHICAL_STATE_BACKGROUND_COLOR);
     544          147 :             ++f_param_pos;
     545          147 :             break;
     546              : 
     547            7 :         case 50:
     548            7 :             update_style(0, GRAPHICAL_STATE_PROPORTIONAL);
     549            7 :             ++f_param_pos;
     550            7 :             break;
     551              : 
     552          140 :         case 53:
     553          140 :             update_style(GRAPHICAL_STATE_OVERLINE);
     554          140 :             ++f_param_pos;
     555          140 :             break;
     556              : 
     557            7 :         case 55:
     558            7 :             update_style(0, GRAPHICAL_STATE_OVERLINE);
     559            7 :             ++f_param_pos;
     560            7 :             break;
     561              : 
     562           21 :         case 58:
     563           21 :             f_underline_color = get_color(false);
     564           21 :             update_style(GRAPHICAL_STATE_UNDERLINE_COLOR);
     565           21 :             break;
     566              : 
     567           14 :         case 59:
     568           14 :             f_underline_color = 0;
     569           14 :             update_style(0, GRAPHICAL_STATE_UNDERLINE_COLOR);
     570           14 :             ++f_param_pos;
     571           14 :             break;
     572              : 
     573           28 :         case 73:
     574           28 :             update_style(GRAPHICAL_STATE_SUPERSCRIPT, GRAPHICAL_STATE_SUBSCRIPT);
     575           28 :             ++f_param_pos;
     576           28 :             break;
     577              : 
     578           28 :         case 74:
     579           28 :             update_style(GRAPHICAL_STATE_SUBSCRIPT, GRAPHICAL_STATE_SUPERSCRIPT);
     580           28 :             ++f_param_pos;
     581           28 :             break;
     582              : 
     583           28 :         case 75:
     584           28 :             update_style(0, GRAPHICAL_STATE_SUBSCRIPT | GRAPHICAL_STATE_SUPERSCRIPT);
     585           28 :             ++f_param_pos;
     586           28 :             break;
     587              : 
     588           56 :         case 90:
     589              :         case 91:
     590              :         case 92:
     591              :         case 93:
     592              :         case 94:
     593              :         case 95:
     594              :         case 96:
     595              :         case 97:
     596              :             // the next 8 colors are the "bright" CSI colors
     597              :             //
     598           56 :             f_foreground_color = g_colors[f_parameters[f_param_pos] - (90 - 8)];
     599           56 :             update_style(GRAPHICAL_STATE_FOREGROUND_COLOR);
     600           56 :             ++f_param_pos;
     601           56 :             break;
     602              : 
     603           56 :         case 100:
     604              :         case 101:
     605              :         case 102:
     606              :         case 103:
     607              :         case 104:
     608              :         case 105:
     609              :         case 106:
     610              :         case 107:
     611              :             // the next 8 colors are the "bright" CSI colors
     612              :             //
     613           56 :             f_background_color = g_colors[f_parameters[f_param_pos] - (100 - 8)];
     614           56 :             update_style(GRAPHICAL_STATE_BACKGROUND_COLOR);
     615           56 :             ++f_param_pos;
     616           56 :             break;
     617              : 
     618              :         // ignore the following
     619              :         //
     620          140 :         case 10: // fonts
     621              :         case 11:
     622              :         case 12:
     623              :         case 13:
     624              :         case 14:
     625              :         case 15:
     626              :         case 16:
     627              :         case 17:
     628              :         case 18:
     629              :         case 19:
     630              :         case 20:
     631              :         case 51: // framed
     632              :         case 52: // encircled
     633              :         case 54: // cancel framed / encircled
     634              :         case 60: // ideogram
     635              :         case 61:
     636              :         case 62:
     637              :         case 63:
     638              :         case 64:
     639              :         case 65:
     640          140 :             ++f_param_pos;
     641          140 :             break;
     642              : 
     643          100 :         default:
     644              :             // undefined, that means invalid
     645              :             //
     646          100 :             f_invalid_input = true;
     647          100 :             f_param_pos = -1;
     648          100 :             break;
     649              : 
     650              :         }
     651              :     }
     652      1114046 : }
     653              : 
     654              : 
     655          122 : std::int32_t convert_ansi::get_color(bool support_transparent)
     656              : {
     657          122 :     if(f_parameters.size() >= static_cast<std::size_t>(f_param_pos) + 2UL)
     658              :     {
     659          122 :         switch(f_parameters[f_param_pos + 1])
     660              :         {
     661              :         //case 0: // app. specific, we do not support that one
     662              : 
     663           16 :         case 1:
     664           16 :             if(support_transparent)
     665              :             {
     666           14 :                 f_param_pos += 2;
     667           14 :                 return -1;
     668              :             }
     669            2 :             break;
     670              : 
     671           41 :         case 2:
     672           41 :             if(f_parameters.size() >= static_cast<std::size_t>(f_param_pos) + 5UL)
     673              :             {
     674           38 :                 if(f_parameters[f_param_pos + 2] < 256
     675           37 :                 && f_parameters[f_param_pos + 3] < 256
     676           75 :                 && f_parameters[f_param_pos + 4] < 256)
     677              :                 {
     678              :                     // RGB
     679              :                     std::int32_t const color(
     680           35 :                           (f_parameters[f_param_pos + 2] << 16)
     681           35 :                         | (f_parameters[f_param_pos + 3] <<  8)
     682           35 :                         | (f_parameters[f_param_pos + 4] <<  0));
     683           35 :                     f_param_pos += 5;
     684           35 :                     return color;
     685              :                 }
     686              :             }
     687            6 :             break;
     688              : 
     689           20 :         case 3:
     690           20 :             if(f_parameters.size() >= static_cast<std::size_t>(f_param_pos) + 5UL)
     691              :             {
     692           17 :                 if(f_parameters[f_param_pos + 2] < 256
     693           16 :                 && f_parameters[f_param_pos + 3] < 256
     694           33 :                 && f_parameters[f_param_pos + 4] < 256)
     695              :                 {
     696              :                     // CMY -> RGB
     697              :                     std::int32_t const color(
     698           14 :                           ((255 - f_parameters[f_param_pos + 2]) << 16)
     699           14 :                         | ((255 - f_parameters[f_param_pos + 3]) <<  8)
     700           14 :                         | ((255 - f_parameters[f_param_pos + 4]) <<  0));
     701           14 :                     f_param_pos += 5;
     702           14 :                     return color;
     703              :                 }
     704              :             }
     705            6 :             break;
     706              : 
     707           22 :         case 4:
     708           22 :             if(f_parameters.size() >= static_cast<std::size_t>(f_param_pos) + 6UL)
     709              :             {
     710           18 :                 if(f_parameters[f_param_pos + 2] < 256
     711           17 :                 && f_parameters[f_param_pos + 3] < 256
     712           16 :                 && f_parameters[f_param_pos + 4] < 256
     713           35 :                 && f_parameters[f_param_pos + 5] < 256)
     714              :                 {
     715              :                     // CMYK -> RGB
     716           14 :                     int const percent(255 - f_parameters[f_param_pos + 5]);
     717              :                     std::int32_t const color(
     718           14 :                           (((255 - f_parameters[f_param_pos + 2]) * percent / 255) << 16)
     719           14 :                         | (((255 - f_parameters[f_param_pos + 3]) * percent / 255) <<  8)
     720           14 :                         | (((255 - f_parameters[f_param_pos + 4]) * percent / 255) <<  0));
     721           14 :                     f_param_pos += 6;
     722           14 :                     return color;
     723              :                 }
     724              :             }
     725            8 :             break;
     726              : 
     727           23 :         case 5:
     728           23 :             if(f_parameters.size() >= static_cast<std::size_t>(f_param_pos) + 3UL)
     729              :             {
     730           22 :                 if(f_parameters[f_param_pos + 2] < 256)
     731              :                 {
     732           21 :                     std::int32_t const color(g_colors[f_parameters[f_param_pos + 2]]);
     733           21 :                     f_param_pos += 3;
     734           21 :                     return color;
     735              :                 }
     736              :             }
     737            2 :             break;
     738              : 
     739              :         }
     740              :     }
     741           24 :     f_param_pos = -1;
     742           24 :     f_invalid_input = true;
     743              : 
     744           24 :     return 0;
     745              : }
     746              : 
     747              : 
     748      2226039 : void convert_ansi::update_style(graphical_state_t new_state, graphical_state_t replaced_states)
     749              : {
     750      2226039 :     f_graphical_state |= new_state;
     751      2226039 :     f_graphical_state &= ~replaced_states;
     752      2226039 : }
     753              : 
     754              : 
     755        14016 : void convert_ansi::start_style()
     756              : {
     757              :     // is that state already set?
     758              :     // if so, we have nothing to do here
     759              :     //
     760        14016 :     if(f_graphical_state == f_current_graphical_state)
     761              :     {
     762        13137 :         return;
     763              :     }
     764          879 :     end_style();
     765          879 :     f_current_graphical_state = f_graphical_state;
     766              : 
     767              :     // when clearing we may end up with no more graphical style
     768              :     //
     769          879 :     if(f_current_graphical_state == GRAPHICAL_STATE_NORMAL)
     770              :     {
     771          285 :         return;
     772              :     }
     773              : 
     774          594 :     if(f_type == ansi_output_t::ANSI_OUTPUT_HTML)
     775              :     {
     776          495 :         open_span();
     777              :     }
     778              :     else
     779              :     {
     780           99 :         start_markdown();
     781              :     }
     782              : }
     783              : 
     784              : 
     785      1113833 : void convert_ansi::end_style()
     786              : {
     787      1113833 :     if(f_current_graphical_state != GRAPHICAL_STATE_NORMAL)
     788              :     {
     789          594 :         if(f_type == ansi_output_t::ANSI_OUTPUT_HTML)
     790              :         {
     791          495 :             close_span();
     792              :         }
     793              :         else
     794              :         {
     795           99 :             end_markdown();
     796              :         }
     797              :     }
     798      1113833 : }
     799              : 
     800              : 
     801          495 : void convert_ansi::open_span()
     802              : {
     803          495 :     std::list<std::string> tags;
     804          495 :     std::list<std::string> classes;
     805              : 
     806          495 :     f_graphical_state_for_styles |= f_current_graphical_state;
     807              : 
     808          495 :     if((f_current_graphical_state & GRAPHICAL_STATE_BOLD) != 0)
     809              :     {
     810           10 :         if(f_optimize)
     811              :         {
     812           12 :             tags.push_back("<b>");
     813              :         }
     814              :         else
     815              :         {
     816           18 :             classes.push_back("ansi-b");
     817              :         }
     818              :     }
     819              : 
     820          495 :     if((f_current_graphical_state & GRAPHICAL_STATE_LIGHT) != 0)
     821              :     {
     822           30 :         classes.push_back("ansi-l");
     823              :     }
     824              : 
     825          495 :     if((f_current_graphical_state & GRAPHICAL_STATE_ITALIC) != 0)
     826              :     {
     827           10 :         if(f_optimize)
     828              :         {
     829           12 :             tags.push_back("<i>");
     830              :         }
     831              :         else
     832              :         {
     833           18 :             classes.push_back("ansi-i");
     834              :         }
     835              :     }
     836              : 
     837          495 :     if((f_current_graphical_state & GRAPHICAL_STATE_SLOW_BLINK) != 0)
     838              :     {
     839           30 :         classes.push_back("ansi-sb");
     840              :     }
     841              : 
     842          495 :     if((f_current_graphical_state & GRAPHICAL_STATE_FAST_BLINK) != 0)
     843              :     {
     844           30 :         classes.push_back("ansi-fb");
     845              :     }
     846              : 
     847          495 :     if((f_current_graphical_state & GRAPHICAL_STATE_PROPORTIONAL) != 0)
     848              :     {
     849           15 :         classes.push_back("ansi-p");
     850              :     }
     851              : 
     852          495 :     if((f_current_graphical_state & GRAPHICAL_STATE_SUPERSCRIPT) != 0)
     853              :     {
     854           20 :         if(f_optimize)
     855              :         {
     856           24 :             tags.push_back("<sup>");
     857              :         }
     858              :         else
     859              :         {
     860           36 :             classes.push_back("ansi-sup");
     861              :         }
     862              :     }
     863              : 
     864          495 :     if((f_current_graphical_state & GRAPHICAL_STATE_SUBSCRIPT) != 0)
     865              :     {
     866           20 :         if(f_optimize)
     867              :         {
     868           24 :             tags.push_back("<sub>");
     869              :         }
     870              :         else
     871              :         {
     872           36 :             classes.push_back("ansi-sub");
     873              :         }
     874              :     }
     875              : 
     876          495 :     switch(f_current_graphical_state & (GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT))
     877              :     {
     878          330 :     case 0:
     879          330 :         break;
     880              : 
     881           25 :     case GRAPHICAL_STATE_UNDERLINE:
     882           25 :         if(f_optimize)
     883              :         {
     884           30 :             tags.push_back("<u>");
     885              :         }
     886              :         else
     887              :         {
     888           45 :             classes.push_back("ansi-u");
     889              :         }
     890           25 :         break;
     891              : 
     892           10 :     case GRAPHICAL_STATE_DOUBLE_UNDERLINE:
     893           30 :         classes.push_back("ansi-d");
     894           10 :         break;
     895              : 
     896           10 :     case GRAPHICAL_STATE_OVERLINE:
     897           30 :         classes.push_back("ansi-v");
     898           10 :         break;
     899              : 
     900           10 :     case GRAPHICAL_STATE_CROSS_OUT:
     901           10 :         if(f_optimize)
     902              :         {
     903           12 :             tags.push_back("<s>");
     904              :         }
     905              :         else
     906              :         {
     907           18 :             classes.push_back("ansi-s");
     908              :         }
     909           10 :         break;
     910              : 
     911           10 :     case GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_CROSS_OUT:
     912           30 :         classes.push_back("ansi-ds");
     913           10 :         break;
     914              : 
     915           10 :     case GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE:
     916           30 :         classes.push_back("ansi-dv");
     917           10 :         break;
     918              : 
     919           30 :     case GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT:
     920           90 :         classes.push_back("ansi-dvs");
     921           30 :         break;
     922              : 
     923           10 :     case GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_CROSS_OUT:
     924           10 :         if(f_optimize)
     925              :         {
     926           12 :             tags.push_back("<u><s>");
     927              :         }
     928              :         else
     929              :         {
     930           18 :             classes.push_back("ansi-us");
     931              :         }
     932           10 :         break;
     933              : 
     934           10 :     case GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_OVERLINE:
     935           30 :         classes.push_back("ansi-uv");
     936           10 :         break;
     937              : 
     938           30 :     case GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT:
     939           90 :         classes.push_back("ansi-uvs");
     940           30 :         break;
     941              : 
     942           10 :     case GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT:
     943           30 :         classes.push_back("ansi-vs");
     944           10 :         break;
     945              : 
     946              :     // LCOV_EXCL_START
     947              :     default:
     948              :         throw logger_logic_error(
     949              :               "unhandled underline + double underline + overline + cross out case (0x"
     950              :             + snapdev::int_to_hex(f_current_graphical_state & (GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT), false, 4)
     951              :             + ")");
     952              :     // LCOV_EXCL_STOP
     953              : 
     954              :     }
     955              : 
     956         1485 :     f_result += snapdev::join_strings(tags, "");
     957              : 
     958          495 :     bool add_colors(false);
     959          495 :     std::int32_t foreground_color(0x000000);
     960          495 :     std::int32_t background_color(0xffffff);
     961              : 
     962          495 :     if((f_current_graphical_state & GRAPHICAL_STATE_FOREGROUND_COLOR) != 0)
     963              :     {
     964          115 :         add_colors = true;
     965          115 :         foreground_color = f_foreground_color;
     966              :     }
     967              : 
     968          495 :     if((f_current_graphical_state & GRAPHICAL_STATE_BACKGROUND_COLOR) != 0)
     969              :     {
     970          105 :         add_colors = true;
     971          105 :         background_color = f_background_color;
     972              :     }
     973              : 
     974          495 :     if((f_current_graphical_state & GRAPHICAL_STATE_INVERSE) != 0
     975           25 :     && foreground_color != -1)
     976              :     {
     977           20 :         add_colors = true;
     978           20 :         std::swap(foreground_color, background_color);
     979              :     }
     980              : 
     981          495 :     bool const add_underline_color((f_current_graphical_state & GRAPHICAL_STATE_UNDERLINE_COLOR) != 0);
     982              : 
     983          495 :     if(!classes.empty() || add_colors || add_underline_color)
     984              :     {
     985          455 :         f_span_open = true;
     986          455 :         f_result += "<span";
     987              : 
     988          455 :         if(!classes.empty())
     989              :         {
     990          218 :             f_result += " class=\"";
     991          654 :             f_result += snapdev::join_strings(classes, " ");
     992          218 :             f_result += '"';
     993              :         }
     994              : 
     995          455 :         if(add_colors || add_underline_color)
     996              :         {
     997          240 :             f_result += " style=\"";
     998          240 :             if(add_colors)
     999              :             {
    1000          235 :                 if(foreground_color != -1)
    1001              :                 {
    1002          225 :                     f_result += "color:#";
    1003          225 :                     f_result += snapdev::int_to_hex(foreground_color, false, 6);
    1004              :                 }
    1005              :                 else
    1006              :                 {
    1007           10 :                     f_result += "opacity:0%";
    1008              :                 }
    1009          235 :                 f_result += ";background-color:#";
    1010          235 :                 f_result += snapdev::int_to_hex(background_color, false, 6);
    1011              :             }
    1012          240 :             if(add_underline_color)
    1013              :             {
    1014           10 :                 if(add_colors)
    1015              :                 {
    1016            5 :                     f_result += ';';
    1017              :                 }
    1018           10 :                 f_result += "text-decoration-color:#";
    1019           10 :                 f_result += snapdev::int_to_hex(f_underline_color, false, 6);
    1020              :             }
    1021          240 :             f_result += '"';
    1022              :         }
    1023              : 
    1024          455 :         f_result += '>';
    1025              :     }
    1026          990 : }
    1027              : 
    1028              : 
    1029          495 : void convert_ansi::close_span()
    1030              : {
    1031          495 :     if(f_span_open)
    1032              :     {
    1033          455 :         f_result += "</span>";
    1034          455 :         f_span_open = false;
    1035              :     }
    1036              : 
    1037          495 :     if(f_optimize)
    1038              :     {
    1039          198 :         switch(f_current_graphical_state & (GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT))
    1040              :         {
    1041           10 :         case GRAPHICAL_STATE_UNDERLINE:
    1042           10 :             f_result += "</u>";
    1043           10 :             break;
    1044              : 
    1045            4 :         case GRAPHICAL_STATE_CROSS_OUT:
    1046            4 :             f_result += "</s>";
    1047            4 :             break;
    1048              : 
    1049            4 :         case GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_CROSS_OUT:
    1050            4 :             f_result += "</s></u>";
    1051            4 :             break;
    1052              : 
    1053          180 :         default:
    1054              :             // other cases make use of the <span> tag
    1055          180 :             break;
    1056              : 
    1057              :         }
    1058          198 :         if((f_current_graphical_state & GRAPHICAL_STATE_SUBSCRIPT) != 0)
    1059              :         {
    1060            8 :             f_result += "</sub>";
    1061              :         }
    1062          198 :         if((f_current_graphical_state & GRAPHICAL_STATE_SUPERSCRIPT) != 0)
    1063              :         {
    1064            8 :             f_result += "</sup>";
    1065              :         }
    1066          198 :         if((f_current_graphical_state & GRAPHICAL_STATE_ITALIC) != 0)
    1067              :         {
    1068            4 :             f_result += "</i>";
    1069              :         }
    1070          198 :         if((f_current_graphical_state & GRAPHICAL_STATE_BOLD) != 0)
    1071              :         {
    1072            4 :             f_result += "</b>";
    1073              :         }
    1074              :     }
    1075          495 : }
    1076              : 
    1077              : 
    1078           99 : void convert_ansi::start_markdown()
    1079              : {
    1080           99 :     if((f_current_graphical_state & GRAPHICAL_STATE_BOLD) != 0)
    1081              :     {
    1082            2 :         f_result += "*";
    1083              :     }
    1084           99 :     if((f_current_graphical_state & GRAPHICAL_STATE_ITALIC) != 0)
    1085              :     {
    1086            2 :         f_result += "**";
    1087              :     }
    1088           99 : }
    1089              : 
    1090              : 
    1091           99 : void convert_ansi::end_markdown()
    1092              : {
    1093           99 :     if((f_current_graphical_state & GRAPHICAL_STATE_ITALIC) != 0)
    1094              :     {
    1095            2 :         f_result += "**";
    1096              :     }
    1097           99 :     if((f_current_graphical_state & GRAPHICAL_STATE_BOLD) != 0)
    1098              :     {
    1099            2 :         f_result += "*";
    1100              :     }
    1101           99 : }
    1102              : 
    1103              : 
    1104              : /** \brief Get the HTML styles to add to your style tag.
    1105              :  *
    1106              :  * After you are done with the read() function, you must call this function
    1107              :  * to get all the styles. For the most part, the tags are assigned classes
    1108              :  * and these are defined in these styles.
    1109              :  *
    1110              :  * Note that the function does not generate the `<style>` tag. That way you
    1111              :  * can include these in your existing tag.
    1112              :  *
    1113              :  * I use abbreviations to make the names shorter:
    1114              :  *
    1115              :  * * bold -- b
    1116              :  * * cross out -- s
    1117              :  * * double underline -- d
    1118              :  * * double underline + cross out -- ds
    1119              :  * * double underline + overline -- dv
    1120              :  * * double underline + overline + cross out -- dvs
    1121              :  * * fast blink -- fb
    1122              :  * * italic -- i
    1123              :  * * light -- l
    1124              :  * * outline -- o
    1125              :  * * overline -- v
    1126              :  * * overline + cross out -- vs
    1127              :  * * proportional -- p
    1128              :  * * slow blink -- sb
    1129              :  * * subscript -- sub
    1130              :  * * superscript -- sup
    1131              :  * * underline -- u
    1132              :  * * underline + cross out -- us
    1133              :  * * underline + overline -- uv
    1134              :  * * underline + overline + cross out -- uvs
    1135              :  *
    1136              :  * \param[in] apply_to_defaults  Whether the default optimization tags should
    1137              :  * be tweaked by this CSS code.
    1138              :  *
    1139              :  * \return Styles that can be added inside your main \<style> tag.
    1140              :  */
    1141          582 : std::string convert_ansi::get_styles(bool apply_to_detauls) const
    1142              : {
    1143          582 :     std::string styles;
    1144              : 
    1145          582 :     if(f_type == ansi_output_t::ANSI_OUTPUT_HTML)
    1146              :     {
    1147          372 :         if((f_graphical_state_for_styles & GRAPHICAL_STATE_BOLD) != 0)
    1148              :         {
    1149            6 :             if(apply_to_detauls && f_optimize)
    1150              :             {
    1151            2 :                 styles += "b,";
    1152              :             }
    1153            6 :             styles += ".ansi-b{font-weight:bold}\n";
    1154              :         }
    1155              : 
    1156          372 :         if((f_graphical_state_for_styles & GRAPHICAL_STATE_LIGHT) != 0)
    1157              :         {
    1158            6 :             styles += ".ansi-l{font-weight:light}\n";
    1159              :         }
    1160              : 
    1161          372 :         if((f_graphical_state_for_styles & GRAPHICAL_STATE_ITALIC) != 0)
    1162              :         {
    1163            6 :             if(apply_to_detauls && f_optimize)
    1164              :             {
    1165            2 :                 styles += "i,";
    1166              :             }
    1167            6 :             styles += ".ansi-i{font-style:italic}\n";
    1168              :         }
    1169              : 
    1170          372 :         if((f_graphical_state_for_styles & (GRAPHICAL_STATE_SLOW_BLINK | GRAPHICAL_STATE_FAST_BLINK)) != 0)
    1171              :         {
    1172           12 :             styles += "@keyframes ansi-blinker{50%{opacity:0}}\n";
    1173              :         }
    1174              : 
    1175          372 :         if((f_graphical_state_for_styles & GRAPHICAL_STATE_SLOW_BLINK) != 0)
    1176              :         {
    1177            6 :             styles += ".ansi-sb{animation:ansi-blinker 2s linear infinite}\n";
    1178              :         }
    1179              : 
    1180          372 :         if((f_graphical_state_for_styles & GRAPHICAL_STATE_FAST_BLINK) != 0)
    1181              :         {
    1182            6 :             styles += ".ansi-fb{animation:ansi-blinker 0.4s linear infinite}\n";
    1183              :         }
    1184              : 
    1185          372 :         if((f_graphical_state_for_styles & GRAPHICAL_STATE_PROPORTIONAL) != 0)
    1186              :         {
    1187            3 :             styles += ".ansi-p{font-family:sans-serif}\n";
    1188              :         }
    1189              : 
    1190          372 :         if((f_graphical_state_for_styles & GRAPHICAL_STATE_SUPERSCRIPT) != 0)
    1191              :         {
    1192           12 :             if(apply_to_detauls && f_optimize)
    1193              :             {
    1194            4 :                 styles += "sup,";
    1195              :             }
    1196           12 :             styles += ".ansi-sup{font-size:60%;vertical-align:super}\n";
    1197              :         }
    1198              : 
    1199          372 :         if((f_graphical_state_for_styles & GRAPHICAL_STATE_SUBSCRIPT) != 0)
    1200              :         {
    1201           12 :             if(apply_to_detauls && f_optimize)
    1202              :             {
    1203            4 :                 styles += "sub,";
    1204              :             }
    1205           12 :             styles += ".ansi-sub{font-size:60%;vertical-align:sub}\n";
    1206              :         }
    1207              : 
    1208              :         // TODO: the following if() test is a simplification, we could change
    1209              :         //       that to only include the classes we used instead
    1210              :         //
    1211          372 :         if((f_graphical_state_for_styles & (GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT)) != 0)
    1212              :         {
    1213              :             // Note:  The double style applies to both, the overline and
    1214              :             //        the underline; in the XTerm console, though it
    1215              :             //        only applies to the underline; to simplify here
    1216              :             //        especially since I've never seen it used anyway,
    1217              :             //        I keep it as is (double on both ends)
    1218              : 
    1219              :             // CROSS OUT on its own
    1220              :             //
    1221           93 :             if(apply_to_detauls && f_optimize)
    1222              :             {
    1223           31 :                 styles += "s,";
    1224              :             }
    1225           93 :             styles += ".ansi-s{text-decoration-line:line-through}\n";
    1226              : 
    1227              :             // UNDERLINE on its own
    1228              :             //
    1229           93 :             if(apply_to_detauls && f_optimize)
    1230              :             {
    1231           31 :                 styles += "u,";
    1232              :             }
    1233           93 :             styles += ".ansi-u{text-decoration-line:underline}\n";
    1234              : 
    1235              :             // DOUBLE UNDERLINE on its own
    1236              :             //
    1237           93 :             styles += ".ansi-d{text-decoration-line:underline;text-decoration-style:double}\n";
    1238              : 
    1239              :             // OVERLINE on its own
    1240              :             //
    1241           93 :             styles += ".ansi-v{text-decoration-line:overline;}\n";
    1242              : 
    1243              :             // UNDERLINE + CROSS OUT
    1244              :             //
    1245           93 :             styles += ".ansi-us{text-decoration-line:underline line-through}\n";
    1246              : 
    1247              :             // UNDERLINE + OVERLINE
    1248              :             //
    1249           93 :             styles += ".ansi-uv{text-decoration-line:underline overline}\n";
    1250              : 
    1251              :             // UNDERLINE + OVERLINE + CROSS OUT
    1252              :             //
    1253           93 :             styles += ".ansi-uvs{text-decoration-line:underline overline line-through}\n";
    1254              : 
    1255              :             // DOUBLE UNDERLINE + CROSS OUT
    1256              :             //
    1257           93 :             styles += ".ansi-ds{text-decoration-line:underline line-through;text-decoration-style:double}\n";
    1258              : 
    1259              :             // DOUBLE UNDERLINE + OVERLINE
    1260              :             //
    1261           93 :             styles += ".ansi-dv{text-decoration-line:underline overline;text-decoration-style:double}\n";
    1262              : 
    1263              :             // DOUBLE UNDERLINE + OVERLINE + CROSS OUT
    1264              :             //
    1265           93 :             styles += ".ansi-dvs{text-decoration-line:underline overline line-through;text-decoration-style:double}\n";
    1266              : 
    1267              :             // OVERLINE + CROSS OUT
    1268              :             //
    1269           93 :             styles += ".ansi-vs{text-decoration-line:overline line-through}\n";
    1270              :         }
    1271              :     }
    1272              : 
    1273          582 :     return styles;
    1274              : } // LCOV_EXCL_LINE
    1275              : 
    1276              : 
    1277              : /** \brief Check whether any of the input was considered invalid.
    1278              :  *
    1279              :  * If the input data could not be read 100% without errors (skipping
    1280              :  * sequence of unknown character sequences) then this function returns
    1281              :  * true to signal that there was at least one error.
    1282              :  *
    1283              :  * \return true if a sequence of bytes in the input was not considered valid.
    1284              :  */
    1285      1112891 : bool convert_ansi::has_invalid_data() const
    1286              : {
    1287      1112891 :     return f_invalid_input;
    1288              : }
    1289              : 
    1290              : 
    1291              : /** \brief Get the following character as a Unicode value.
    1292              :  *
    1293              :  * This function reads the input data for one character. It converts
    1294              :  * the character to a full char32_t character (i.e. a Unicode rune).
    1295              :  *
    1296              :  * \todo
    1297              :  * A Unicode character sequence that ends up being broken in two separate
    1298              :  * strings (see write()) is not properly recognized. We'd need to support
    1299              :  * such one day.
    1300              :  *
    1301              :  * \return The Unicode character or libutf8::EOS if no more data is available.
    1302              :  */
    1303      7816684 : char32_t convert_ansi::getc()
    1304              : {
    1305      8929576 :     while(!f_data.empty())
    1306              :     {
    1307      7816685 :         if(f_pos >= f_data.front().length())
    1308              :         {
    1309      1112891 :             f_data.pop_front();
    1310      1112891 :             f_pos = 0;
    1311              :         }
    1312              :         else
    1313              :         {
    1314      6703794 :             char32_t wc(U'\0');
    1315      6703794 :             char const * end(f_data.front().data() + f_pos);
    1316      6703794 :             char const * start(end);
    1317      6703794 :             std::size_t len(f_data.front().length() - f_pos);
    1318      6703794 :             int const r(libutf8::mbstowc(wc, end, len));
    1319              : 
    1320              :             // on invalid UTF-8 sequences, we may skip many bytes at once
    1321              :             // the following takes that in account
    1322              :             //
    1323      6703794 :             f_pos += end - start;
    1324              : 
    1325      6703794 :             if(r > 0)
    1326              :             {
    1327      6703793 :                 return wc;
    1328              :             }
    1329              :             // if r == 0, we reached the end of the string
    1330              :             // otherwise we got an error and want to make a note of that
    1331              :             //
    1332            1 :             if(r != 0)
    1333              :             {
    1334            1 :                 f_invalid_input = true;
    1335              :             }
    1336              :         }
    1337              :     }
    1338              : 
    1339              :     // done, no more input data
    1340              :     //
    1341      1112891 :     return libutf8::EOS;
    1342              : }
    1343              : 
    1344              : 
    1345              : 
    1346              : }
    1347              : // namespace snaplogger
    1348              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions