LCOV - code coverage report
Current view: top level - snaplogger - system_functions.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 164 164 100.0 %
Date: 2022-01-29 21:11:29 Functions: 46 57 80.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2013-2021  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 Variables are used to dynamically add parameters to log messages.
      22             :  *
      23             :  * This file declares the base variable class.
      24             :  *
      25             :  * The format defines \em functions which are written as in
      26             :  * `${function-name}`.
      27             :  *
      28             :  * Parameters can be passed to these functions by adding `:<param>`
      29             :  * to those definitions. These are named parameters and their default
      30             :  * value is "present" or not. A specific value can be assignd using
      31             :  * the equal sign as in `:param=<value>`.
      32             :  *
      33             :  * For example, the date function can be called as follow:
      34             :  *
      35             :  * \code
      36             :  *     ${date:year:align=right:exact_width=2}
      37             :  * \endcode
      38             :  *
      39             :  * The `year` parameter is specific to the `date` function. The other
      40             :  * parameters are available whatever the function. This variable asks
      41             :  * to truncate the year to 2 character right aligned (i.e. "18" in
      42             :  * "2018".)
      43             :  *
      44             :  * In C, this would look something like:
      45             :  *
      46             :  * \code
      47             :  *     date(FLAG_YEAR, ALIGN_RIGHT, 2);
      48             :  * \endcode
      49             :  */
      50             : 
      51             : 
      52             : // self
      53             : //
      54             : #include    "snaplogger/exception.h"
      55             : #include    "snaplogger/guard.h"
      56             : #include    "snaplogger/variable.h"
      57             : 
      58             : 
      59             : // libutf8 lib
      60             : //
      61             : #include    <libutf8/libutf8.h>
      62             : 
      63             : 
      64             : // snapdev lib
      65             : //
      66             : #include    <snapdev/not_used.h>
      67             : 
      68             : 
      69             : // C++ lib
      70             : //
      71             : #include    <algorithm>
      72             : #include    <iostream>
      73             : #include    <queue>
      74             : 
      75             : 
      76             : // last include
      77             : //
      78             : #include    <snapdev/poison.h>
      79             : 
      80             : 
      81             : 
      82             : namespace snaplogger
      83             : {
      84             : 
      85             : 
      86             : 
      87             : namespace
      88             : {
      89             : 
      90             : 
      91             : 
      92             : //
      93             : // Change Parameters
      94             : //
      95             : 
      96             : 
      97          28 : DECLARE_FUNCTION(padding)
      98             : {
      99          20 :     snapdev::NOT_USED(msg);
     100             : 
     101          40 :     std::u32string pad;
     102          20 :     if(p->get_type() == param::type_t::TYPE_STRING)
     103             :     {
     104          18 :         pad = libutf8::to_u32string(p->get_value());
     105             :     }
     106             :     else
     107             :     {
     108           2 :         std::int64_t const digit(p->get_integer());
     109           2 :         if(digit < 0 || digit > 9)
     110             :         {
     111             :             throw invalid_parameter(
     112             :                       "the ${...:padding=<value>} when set to a number must be one digit ('0' to '9'), not \""
     113           2 :                     + std::to_string(digit)
     114           3 :                     + "\".");
     115             :         }
     116           1 :         pad = libutf8::to_u32string(std::to_string(digit));
     117             :     }
     118          19 :     if(pad.length() == 1)
     119             :     {
     120          18 :         d.set_param(std::string("padding"), pad);
     121             :     }
     122             :     else
     123             :     {
     124             :         throw invalid_parameter(
     125             :                   "the ${...:padding=' '} must be exactly one character, not \""
     126           2 :                 + p->get_value()
     127           3 :                 + "\".");
     128             :     }
     129          18 : }
     130             : 
     131             : 
     132          26 : DECLARE_FUNCTION(align)
     133             : {
     134          18 :     snapdev::NOT_USED(msg);
     135             : 
     136          18 :     if(p->get_value() == "left")
     137             :     {
     138           4 :         d.set_param("align", "L");
     139             :     }
     140          13 :     else if(p->get_value() == "right")
     141             :     {
     142           6 :         d.set_param("align", "R");
     143             :     }
     144           7 :     else if(p->get_value() == "center")
     145             :     {
     146           6 :         d.set_param("align", "C");
     147             :     }
     148             :     else
     149             :     {
     150             :         throw invalid_parameter("the ${...:align=left|center|right} was expected, got \""
     151           2 :                               + p->get_value()
     152           3 :                               + "\".");
     153             :     }
     154          16 : }
     155             : 
     156             : 
     157             : 
     158             : 
     159             : 
     160             : //
     161             : // Apply Functions
     162             : //
     163             : 
     164             : 
     165          20 : DECLARE_FUNCTION(max_width)
     166             : {
     167          12 :     snapdev::NOT_USED(msg);
     168             : 
     169          12 :     std::int64_t const max_width(p->get_integer());
     170          12 :     std::int64_t const extra(static_cast<std::int64_t>(d.get_value().length()) - max_width);
     171          12 :     if(extra > 0)
     172             :     {
     173          12 :         char32_t const align(d.get_param("align", U"L")[0]);
     174          12 :         if(align == U'C')
     175             :         {
     176           1 :             d.set_value(d.get_value().substr(extra / 2, max_width));
     177             :         }
     178          11 :         else if(align == U'L')
     179             :         {
     180          10 :             d.get_value().resize(max_width);
     181             :         }
     182             :         else
     183             :         {
     184           1 :             d.set_value(d.get_value().substr(extra));
     185             :         }
     186             :     }
     187          12 : }
     188             : 
     189             : 
     190          13 : DECLARE_FUNCTION(min_width)
     191             : {
     192           5 :     snapdev::NOT_USED(msg);
     193             : 
     194           5 :     std::int64_t const min_width(p->get_integer());
     195           4 :     std::int64_t const pad(min_width - static_cast<std::int64_t>(d.get_value().length()));
     196           4 :     if(pad > 0)
     197             :     {
     198           4 :         char32_t const padding_char(d.get_param("padding", U" ")[0]);
     199           4 :         char32_t const align(d.get_param("align", U"L")[0]);
     200           4 :         if(align == U'C')
     201             :         {
     202           4 :             std::u32string const padding(pad / 2, padding_char);
     203           2 :             d.set_value(padding + d.get_value() + padding);
     204           2 :             if((pad & 1) != 0)
     205             :             {
     206           2 :                 d.get_value() += padding_char;
     207             :             }
     208             :         }
     209             :         else
     210             :         {
     211           4 :             std::u32string const padding(pad, padding_char);
     212           2 :             if(align == U'L')
     213             :             {
     214           1 :                 d.get_value() += padding;
     215             :             }
     216             :             else
     217             :             {
     218           1 :                 d.set_value(padding + d.get_value());
     219             :             }
     220             :         }
     221             :     }
     222           4 : }
     223             : 
     224             : 
     225          17 : DECLARE_FUNCTION(exact_width)
     226             : {
     227           9 :     snapdev::NOT_USED(msg);
     228             : 
     229           9 :     std::int64_t const exact_width(p->get_integer());
     230             : 
     231           9 :     std::int64_t const pad(exact_width - static_cast<std::int64_t>(d.get_value().length()));
     232           9 :     char32_t const align(d.get_param("align", U"L")[0]);
     233           9 :     if(pad > 0)
     234             :     {
     235           6 :         char32_t const padding_char(d.get_param("padding", U" ")[0]);
     236           6 :         if(align == U'C')
     237             :         {
     238           4 :             std::u32string const padding(pad / 2, padding_char);
     239           2 :             d.set_value(padding + d.get_value() + padding);
     240           2 :             if((pad & 1) != 0)
     241             :             {
     242           1 :                 d.get_value() += padding_char;
     243             :             }
     244             :         }
     245             :         else
     246             :         {
     247           8 :             std::u32string const padding(pad, padding_char);
     248           4 :             if(align == U'L')
     249             :             {
     250           1 :                 d.get_value() += padding;
     251             :             }
     252             :             else
     253             :             {
     254           3 :                 d.set_value(padding + d.get_value());
     255             :             }
     256             :         }
     257           6 :         return;
     258             :     }
     259             : 
     260           3 :     if(pad < 0)
     261             :     {
     262           3 :         if(align == U'C')
     263             :         {
     264           1 :             d.set_value(d.get_value().substr(-pad / 2, exact_width));
     265             :         }
     266           2 :         else if(align == U'L')
     267             :         {
     268           1 :             d.get_value().resize(exact_width);
     269             :         }
     270             :         else
     271             :         {
     272           1 :             d.set_value(d.get_value().substr(-pad));
     273             :         }
     274             :     }
     275             : }
     276             : 
     277             : 
     278             : 
     279             : 
     280             : 
     281           9 : DECLARE_FUNCTION(append)
     282             : {
     283           1 :     snapdev::NOT_USED(msg);
     284             : 
     285           2 :     std::string const append_utf8(p->get_value());
     286           2 :     std::u32string const str(libutf8::to_u32string(append_utf8));
     287           1 :     d.get_value() += str;
     288           1 : }
     289             : 
     290           9 : DECLARE_FUNCTION(prepend)
     291             : {
     292           1 :     snapdev::NOT_USED(msg);
     293             : 
     294           2 :     std::string const prepend_utf8(p->get_value());
     295           2 :     std::u32string const prepend(libutf8::to_u32string(prepend_utf8));
     296           1 :     d.set_value(prepend + d.get_value());
     297           1 : }
     298             : 
     299             : 
     300             : 
     301             : 
     302             : 
     303          26 : DECLARE_FUNCTION(escape)
     304             : {
     305          18 :     snapdev::NOT_USED(msg);
     306             : 
     307          36 :     std::string to_escape(p->get_value());
     308          18 :     if(to_escape.empty())
     309             :     {
     310           1 :         to_escape = "\\\n\r\t";
     311             :     }
     312             : 
     313          36 :     std::u32string e(libutf8::to_u32string(to_escape));
     314          36 :     std::u32string r;
     315         789 :     for(auto wc : d.get_value())
     316             :     {
     317         771 :         if(e.find(wc) != std::u32string::npos)
     318             :         {
     319          29 :             if(wc >= 0x80 && wc < 0xA0)
     320             :             {
     321             :                 // "graphical controls"
     322             :                 //
     323           2 :                 r += '@';
     324           2 :                 wc -= 0x40;
     325             :             }
     326          27 :             else if(wc < 0x20)
     327             :             {
     328          11 :                 switch(wc)
     329             :                 {
     330           1 :                 case '\a':
     331           1 :                     r += '\\';
     332           1 :                     wc = U'a';
     333           1 :                     break;
     334             : 
     335           1 :                 case '\b':
     336           1 :                     r += '\\';
     337           1 :                     wc = U'b';
     338           1 :                     break;
     339             : 
     340           1 :                 case '\f':
     341           1 :                     r += '\\';
     342           1 :                     wc = U'f';
     343           1 :                     break;
     344             : 
     345           2 :                 case '\n':
     346           2 :                     r += '\\';
     347           2 :                     wc = U'n';
     348           2 :                     break;
     349             : 
     350           2 :                 case '\r':
     351           2 :                     r += '\\';
     352           2 :                     wc = U'r';
     353           2 :                     break;
     354             : 
     355           2 :                 case '\t':
     356           2 :                     r += '\\';
     357           2 :                     wc = U't';
     358           2 :                     break;
     359             : 
     360           1 :                 case '\v':
     361           1 :                     r += '\\';
     362           1 :                     wc = U'v';
     363           1 :                     break;
     364             : 
     365           1 :                 default:
     366           1 :                     r += '^';
     367           1 :                     wc += 0x40;
     368           1 :                     break;
     369             : 
     370             :                 }
     371             :             }
     372             :             else
     373             :             {
     374          16 :                 r += '\\';
     375             :             }
     376             :         }
     377         771 :         r += wc;
     378             :     }
     379          18 :     d.set_value(r);
     380          18 : }
     381             : 
     382             : 
     383             : 
     384             : 
     385             : 
     386          21 : DECLARE_FUNCTION(caps)
     387             : {
     388          13 :     snapdev::NOT_USED(msg, p);
     389             : 
     390          26 :     std::u32string r;
     391          13 :     bool first(true);
     392         530 :     for(auto wc : d.get_value())
     393             :     {
     394             :         // we should look into having a libutf8::isalpha() function
     395             :         // instead of testing two special cases
     396             :         //
     397         517 :         if(std::isspace(wc)
     398         455 :         || wc == '-')
     399             :         {
     400          75 :             first = true;
     401          75 :             r += wc;
     402             :         }
     403             :         else
     404             :         {
     405             :             // TODO: make use of boost::locale::to_upper(d); so we benefit
     406             :             //       from the current locale (or something close--how do
     407             :             //       you handle multi-chars in this case?!?)
     408             :             //
     409         442 :             if(first)
     410             :             {
     411          78 :                 r += std::towupper(wc);
     412          78 :                 first = false;
     413             :             }
     414             :             else
     415             :             {
     416         364 :                 r += std::towlower(wc);
     417             :             }
     418             :         }
     419             :     }
     420          13 :     d.set_value(r);
     421          13 : }
     422             : 
     423           9 : DECLARE_FUNCTION(lower)
     424             : {
     425           1 :     snapdev::NOT_USED(msg, p);
     426             : 
     427             :     // TODO: make use of boost::locale::to_upper(d); so we benefit from the
     428             :     //       current locale
     429             :     //
     430           1 :     std::transform(d.get_value().begin(), d.get_value().end(), d.get_value().begin(), std::towlower);
     431           1 : }
     432             : 
     433          19 : DECLARE_FUNCTION(upper)
     434             : {
     435          11 :     snapdev::NOT_USED(msg, p);
     436             : 
     437             :     // TODO: make use of boost::locale::to_upper(d); so we benefit from the
     438             :     //       current locale
     439             :     //
     440          11 :     std::transform(d.get_value().begin(), d.get_value().end(), d.get_value().begin(), std::towupper);
     441          11 : }
     442             : 
     443             : 
     444             : 
     445             : 
     446             : }
     447             : // no name namespace
     448             : 
     449             : 
     450             : 
     451             : 
     452             : 
     453             : 
     454             : 
     455           6 : } // snaplogger namespace
     456             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13