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

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

Generated by: LCOV version 1.13