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

Generated by: LCOV version 1.12