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: 2019-12-13 00:59:36 Functions: 46 57 80.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013-2019  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             : // C++ lib
      67             : //
      68             : #include    <iostream>
      69             : #include    <queue>
      70             : 
      71             : 
      72             : // last include
      73             : //
      74             : #include    <snapdev/poison.h>
      75             : 
      76             : 
      77             : 
      78             : namespace snaplogger
      79             : {
      80             : 
      81             : 
      82             : 
      83             : namespace
      84             : {
      85             : 
      86             : 
      87             : 
      88             : //
      89             : // Change Parameters
      90             : //
      91             : 
      92             : 
      93          28 : DECLARE_FUNCTION(padding)
      94             : {
      95          20 :     snap::NOTUSED(msg);
      96             : 
      97          40 :     std::u32string pad;
      98          20 :     if(p->get_type() == param::type_t::TYPE_STRING)
      99             :     {
     100          18 :         pad = libutf8::to_u32string(p->get_value());
     101             :     }
     102             :     else
     103             :     {
     104           2 :         std::int64_t const digit(p->get_integer());
     105           2 :         if(digit < 0 || digit > 9)
     106             :         {
     107             :             throw invalid_parameter(
     108             :                       "the ${...:padding=<value>} when set to a number must be one digit ('0' to '9'), not \""
     109           2 :                     + std::to_string(digit)
     110           3 :                     + "\".");
     111             :         }
     112           1 :         pad = libutf8::to_u32string(std::to_string(digit));
     113             :     }
     114          19 :     if(pad.length() == 1)
     115             :     {
     116          18 :         d.set_param(std::string("padding"), pad);
     117             :     }
     118             :     else
     119             :     {
     120             :         throw invalid_parameter(
     121             :                   "the ${...:padding=' '} must be exactly one character, not \""
     122           2 :                 + p->get_value()
     123           3 :                 + "\".");
     124             :     }
     125          18 : }
     126             : 
     127             : 
     128          26 : DECLARE_FUNCTION(align)
     129             : {
     130          18 :     snap::NOTUSED(msg);
     131             : 
     132          18 :     if(p->get_value() == "left")
     133             :     {
     134           4 :         d.set_param("align", "L");
     135             :     }
     136          13 :     else if(p->get_value() == "right")
     137             :     {
     138           6 :         d.set_param("align", "R");
     139             :     }
     140           7 :     else if(p->get_value() == "center")
     141             :     {
     142           6 :         d.set_param("align", "C");
     143             :     }
     144             :     else
     145             :     {
     146             :         throw invalid_parameter("the ${...:align=left|center|right} was expected, got \""
     147           2 :                               + p->get_value()
     148           3 :                               + "\".");
     149             :     }
     150          16 : }
     151             : 
     152             : 
     153             : 
     154             : 
     155             : 
     156             : //
     157             : // Apply Functions
     158             : //
     159             : 
     160             : 
     161          11 : DECLARE_FUNCTION(max_width)
     162             : {
     163           3 :     snap::NOTUSED(msg);
     164             : 
     165           3 :     std::int64_t const max_width(p->get_integer());
     166           3 :     std::int64_t const extra(static_cast<std::int64_t>(d.get_value().length()) - max_width);
     167           3 :     if(extra > 0)
     168             :     {
     169           3 :         char32_t const align(d.get_param("align", U"L")[0]);
     170           3 :         if(align == U'C')
     171             :         {
     172           1 :             d.set_value(d.get_value().substr(extra / 2, max_width));
     173             :         }
     174           2 :         else if(align == U'L')
     175             :         {
     176           1 :             d.get_value().resize(max_width);
     177             :         }
     178             :         else
     179             :         {
     180           1 :             d.set_value(d.get_value().substr(extra));
     181             :         }
     182             :     }
     183           3 : }
     184             : 
     185             : 
     186          13 : DECLARE_FUNCTION(min_width)
     187             : {
     188           5 :     snap::NOTUSED(msg);
     189             : 
     190           5 :     std::int64_t const min_width(p->get_integer());
     191           4 :     std::int64_t const pad(min_width - static_cast<std::int64_t>(d.get_value().length()));
     192           4 :     if(pad > 0)
     193             :     {
     194           4 :         char32_t const padding_char(d.get_param("padding", U" ")[0]);
     195           4 :         char32_t const align(d.get_param("align", U"L")[0]);
     196           4 :         if(align == U'C')
     197             :         {
     198           4 :             std::u32string const padding(pad / 2, padding_char);
     199           2 :             d.set_value(padding + d.get_value() + padding);
     200           2 :             if((pad & 1) != 0)
     201             :             {
     202           2 :                 d.get_value() += padding_char;
     203             :             }
     204             :         }
     205             :         else
     206             :         {
     207           4 :             std::u32string const padding(pad, padding_char);
     208           2 :             if(align == U'L')
     209             :             {
     210           1 :                 d.get_value() += padding;
     211             :             }
     212             :             else
     213             :             {
     214           1 :                 d.set_value(padding + d.get_value());
     215             :             }
     216             :         }
     217             :     }
     218           4 : }
     219             : 
     220             : 
     221          17 : DECLARE_FUNCTION(exact_width)
     222             : {
     223           9 :     snap::NOTUSED(msg);
     224             : 
     225           9 :     std::int64_t const exact_width(p->get_integer());
     226             : 
     227           9 :     std::int64_t const pad(exact_width - static_cast<std::int64_t>(d.get_value().length()));
     228           9 :     char32_t const align(d.get_param("align", U"L")[0]);
     229           9 :     if(pad > 0)
     230             :     {
     231           6 :         char32_t const padding_char(d.get_param("padding", U" ")[0]);
     232           6 :         if(align == U'C')
     233             :         {
     234           4 :             std::u32string const padding(pad / 2, padding_char);
     235           2 :             d.set_value(padding + d.get_value() + padding);
     236           2 :             if((pad & 1) != 0)
     237             :             {
     238           1 :                 d.get_value() += padding_char;
     239             :             }
     240             :         }
     241             :         else
     242             :         {
     243           8 :             std::u32string const padding(pad, padding_char);
     244           4 :             if(align == U'L')
     245             :             {
     246           1 :                 d.get_value() += padding;
     247             :             }
     248             :             else
     249             :             {
     250           3 :                 d.set_value(padding + d.get_value());
     251             :             }
     252             :         }
     253           6 :         return;
     254             :     }
     255             : 
     256           3 :     if(pad < 0)
     257             :     {
     258           3 :         if(align == U'C')
     259             :         {
     260           1 :             d.set_value(d.get_value().substr(-pad / 2, exact_width));
     261             :         }
     262           2 :         else if(align == U'L')
     263             :         {
     264           1 :             d.get_value().resize(exact_width);
     265             :         }
     266             :         else
     267             :         {
     268           1 :             d.set_value(d.get_value().substr(-pad));
     269             :         }
     270             :     }
     271             : }
     272             : 
     273             : 
     274             : 
     275             : 
     276             : 
     277           9 : DECLARE_FUNCTION(append)
     278             : {
     279           1 :     snap::NOTUSED(msg);
     280             : 
     281           2 :     std::string const append_utf8(p->get_value());
     282           2 :     std::u32string const str(libutf8::to_u32string(append_utf8));
     283           1 :     d.get_value() += str;
     284           1 : }
     285             : 
     286           9 : DECLARE_FUNCTION(prepend)
     287             : {
     288           1 :     snap::NOTUSED(msg);
     289             : 
     290           2 :     std::string const prepend_utf8(p->get_value());
     291           2 :     std::u32string const prepend(libutf8::to_u32string(prepend_utf8));
     292           1 :     d.set_value(prepend + d.get_value());
     293           1 : }
     294             : 
     295             : 
     296             : 
     297             : 
     298             : 
     299          17 : DECLARE_FUNCTION(escape)
     300             : {
     301           9 :     snap::NOTUSED(msg);
     302             : 
     303          18 :     std::string to_escape(p->get_value());
     304           9 :     if(to_escape.empty())
     305             :     {
     306           1 :         to_escape = "\\\n\r\t";
     307             :     }
     308             : 
     309          18 :     std::u32string e(libutf8::to_u32string(to_escape));
     310          18 :     std::u32string r;
     311         414 :     for(auto wc : d.get_value())
     312             :     {
     313         405 :         if(e.find(wc) != std::u32string::npos)
     314             :         {
     315          17 :             if(wc >= 0x80 && wc < 0xA0)
     316             :             {
     317             :                 // "graphical controls"
     318             :                 //
     319           2 :                 r += '@';
     320           2 :                 wc -= 0x40;
     321             :             }
     322          15 :             else if(wc < 0x20)
     323             :             {
     324          11 :                 switch(wc)
     325             :                 {
     326           1 :                 case '\a':
     327           1 :                     r += '\\';
     328           1 :                     wc = U'a';
     329           1 :                     break;
     330             : 
     331           1 :                 case '\b':
     332           1 :                     r += '\\';
     333           1 :                     wc = U'b';
     334           1 :                     break;
     335             : 
     336           1 :                 case '\f':
     337           1 :                     r += '\\';
     338           1 :                     wc = U'f';
     339           1 :                     break;
     340             : 
     341           2 :                 case '\n':
     342           2 :                     r += '\\';
     343           2 :                     wc = U'n';
     344           2 :                     break;
     345             : 
     346           2 :                 case '\r':
     347           2 :                     r += '\\';
     348           2 :                     wc = U'r';
     349           2 :                     break;
     350             : 
     351           2 :                 case '\t':
     352           2 :                     r += '\\';
     353           2 :                     wc = U't';
     354           2 :                     break;
     355             : 
     356           1 :                 case '\v':
     357           1 :                     r += '\\';
     358           1 :                     wc = U'v';
     359           1 :                     break;
     360             : 
     361           1 :                 default:
     362           1 :                     r += '^';
     363           1 :                     wc += 0x40;
     364           1 :                     break;
     365             : 
     366             :                 }
     367             :             }
     368             :             else
     369             :             {
     370           4 :                 r += '\\';
     371             :             }
     372             :         }
     373         405 :         r += wc;
     374             :     }
     375           9 :     d.set_value(r);
     376           9 : }
     377             : 
     378             : 
     379             : 
     380             : 
     381             : 
     382          12 : DECLARE_FUNCTION(caps)
     383             : {
     384           4 :     snap::NOTUSED(msg);
     385           4 :     snap::NOTUSED(p);
     386             : 
     387           8 :     std::u32string r;
     388           4 :     bool first(true);
     389         215 :     for(auto wc : d.get_value())
     390             :     {
     391             :         // we should look into having a libutf8::isalpha() function
     392             :         // instead of testing two special cases
     393             :         //
     394         211 :         if(std::isspace(wc)
     395         185 :         || wc == '-')
     396             :         {
     397          30 :             first = true;
     398          30 :             r += wc;
     399             :         }
     400             :         else
     401             :         {
     402         181 :             if(first)
     403             :             {
     404          33 :                 r += std::towupper(wc);
     405          33 :                 first = false;
     406             :             }
     407             :             else
     408             :             {
     409         148 :                 r += std::towlower(wc);
     410             :             }
     411             :         }
     412             :     }
     413           4 :     d.set_value(r);
     414           4 : }
     415             : 
     416           9 : DECLARE_FUNCTION(lower)
     417             : {
     418           1 :     snap::NOTUSED(msg);
     419           1 :     snap::NOTUSED(p);
     420             : 
     421           1 :     std::transform(d.get_value().begin(), d.get_value().end(), d.get_value().begin(), std::towlower);
     422           1 : }
     423             : 
     424          10 : DECLARE_FUNCTION(upper)
     425             : {
     426           2 :     snap::NOTUSED(msg);
     427           2 :     snap::NOTUSED(p);
     428             : 
     429           2 :     std::transform(d.get_value().begin(), d.get_value().end(), d.get_value().begin(), std::towupper);
     430           2 : }
     431             : 
     432             : 
     433             : 
     434             : 
     435             : }
     436             : // no name namespace
     437             : 
     438             : 
     439             : 
     440             : 
     441             : 
     442             : 
     443             : 
     444           6 : } // snaplogger namespace
     445             : // vim: ts=4 sw=4 et
     446             : 

Generated by: LCOV version 1.13