LCOV - code coverage report
Current view: top level - tools - tldc.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 99 167 59.3 %
Date: 2022-02-19 14:03:34 Functions: 14 16 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* TLD tools -- TLD, domain name, and sub-domain extraction
       2             :  * Copyright (c) 2011-2022  Made to Order Software Corp.  All Rights Reserved
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the
       6             :  * "Software"), to deal in the Software without restriction, including
       7             :  * without limitation the rights to use, copy, modify, merge, publish,
       8             :  * distribute, sublicense, and/or sell copies of the Software, and to
       9             :  * permit persons to whom the Software is furnished to do so, subject to
      10             :  * the following conditions:
      11             :  *
      12             :  * The above copyright notice and this permission notice shall be included
      13             :  * in all copies or substantial portions of the Software.
      14             :  *
      15             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      16             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      17             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      18             :  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
      19             :  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
      20             :  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      21             :  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      22             :  */
      23             : 
      24             : // libtld lib
      25             : //
      26             : #include    <libtld/tld_compiler.h>
      27             : #include    <libtld/tld_file.h>
      28             : 
      29             : 
      30             : // C++ lib
      31             : //
      32             : #include    <fstream>
      33             : #include    <iostream>
      34             : #include    <sstream>
      35             : 
      36             : 
      37             : // C lib
      38             : //
      39             : #include    <string.h>
      40             : 
      41             : 
      42           2 : class compiler
      43             : {
      44             : public:
      45             :     std::ostream &  error();
      46             :     int             exit_code() const;
      47             :     void            set_input_path(std::string const & path);
      48             :     void            set_output(std::string const & output);
      49             :     void            set_c_file(std::string const & c);
      50             :     void            set_verify(bool verify);
      51             :     void            set_output_json(bool verify);
      52             :     void            set_include_offsets(bool include_offsets);
      53             : 
      54             :     void            run();
      55             : 
      56             : private:
      57             :     void            verify_output(tld_compiler & c);
      58             : 
      59             :     int             f_errcnt = 0;
      60             :     std::string     f_input_path = std::string();
      61             :     std::string     f_output = std::string();
      62             :     std::string     f_c_file = std::string();
      63             :     bool            f_verify = false;
      64             :     bool            f_output_json = false;
      65             :     bool            f_include_offsets = false;
      66             : };
      67             : 
      68             : 
      69           0 : std::ostream & compiler::error()
      70             : {
      71           0 :     ++f_errcnt;
      72           0 :     return std::cerr;
      73             : }
      74             : 
      75             : 
      76           1 : int compiler::exit_code() const
      77             : {
      78           1 :     return f_errcnt == 0 ? 0 : 1;
      79             : }
      80             : 
      81             : 
      82           1 : void compiler::set_input_path(std::string const & path)
      83             : {
      84           1 :     f_input_path = path;
      85           1 : }
      86             : 
      87             : 
      88           1 : void compiler::set_output(std::string const & output)
      89             : {
      90           1 :     f_output = output;
      91           1 : }
      92             : 
      93             : 
      94           1 : void compiler::set_c_file(std::string const & c_file)
      95             : {
      96           1 :     f_c_file = c_file;
      97           1 : }
      98             : 
      99             : 
     100           1 : void compiler::set_verify(bool verify)
     101             : {
     102           1 :     f_verify = verify;
     103           1 : }
     104             : 
     105             : 
     106           1 : void compiler::set_output_json(bool output_json)
     107             : {
     108           1 :     f_output_json = output_json;
     109           1 : }
     110             : 
     111             : 
     112           1 : void compiler::set_include_offsets(bool include_offsets)
     113             : {
     114           1 :     f_include_offsets = include_offsets;
     115           1 : }
     116             : 
     117             : 
     118           1 : void compiler::run()
     119             : {
     120           1 :     if(f_errcnt != 0)
     121             :     {
     122             :         // command line found errors, return immediately
     123           0 :         return;
     124             :     }
     125             : 
     126           1 :     if(f_input_path.empty())
     127             :     {
     128           0 :         ++f_errcnt;
     129           0 :         std::cerr << "error: an input path is required.\n";
     130           0 :         return;
     131             :     }
     132             : 
     133           1 :     if(f_output.empty())
     134             :     {
     135           0 :         ++f_errcnt;
     136           0 :         std::cerr << "error: an output filename is required.\n";
     137           0 :         return;
     138             :     }
     139             : 
     140           1 :     std::cout << "Compiling TLDs from \"" << f_input_path << "\"...\n";
     141             : 
     142           2 :     tld_compiler c;
     143           1 :     c.set_input_folder(f_input_path);
     144           1 :     c.set_output(f_output);
     145           1 :     c.set_c_file(f_c_file);
     146           1 :     if(!c.compile())
     147             :     {
     148           0 :         ++f_errcnt;
     149             :         std::cerr
     150             :             << "error:"
     151           0 :             << c.get_filename()
     152           0 :             << ":"
     153             :             << c.get_line()
     154             :             << ": "
     155           0 :             << c.get_errmsg()
     156           0 :             << " (errno: "
     157             :             << c.get_errno()
     158             :             << ", "
     159           0 :             << strerror(c.get_errno())
     160           0 :             << ")\n";
     161           0 :         return;
     162             :     }
     163             : 
     164           1 :     std::cout << "Number of strings:        " << c.get_string_manager().size()         << "\n";
     165           1 :     std::cout << "Longest string:           " << c.get_string_manager().max_length()   << "\n";
     166           1 :     std::cout << "Total string length:      " << c.get_string_manager().total_length() << "\n";
     167           1 :     std::cout << "Included strings:         " << c.get_string_manager().included_count() << " (saved length: " << c.get_string_manager().included_length() << ")\n";
     168           1 :     std::cout << "Mergeable strings:        " << c.get_string_manager().merged_count() << " (saved length: " << c.get_string_manager().merged_length() << ")\n";
     169           1 :     std::cout << "Compressed string length: " << c.get_string_manager().compressed_length() << "\n";
     170             :     // TODO: add info about tags
     171             : 
     172           1 :     if(f_output_json)
     173             :     {
     174           2 :         std::string filename;
     175           1 :         std::string::size_type const dot(f_output.rfind('.'));
     176           1 :         if(dot != std::string::npos
     177           1 :         && dot > 0
     178           2 :         && f_output[dot - 1] != '/')
     179             :         {
     180           1 :             filename = f_output.substr(0, dot) + ".json";
     181             :         }
     182             :         else
     183             :         {
     184           0 :             filename = f_output + ".json";
     185             :         }
     186           2 :         std::ofstream out;
     187           1 :         out.open(filename);
     188           1 :         if(out.is_open())
     189             :         {
     190           1 :             c.output_to_json(out, f_include_offsets);
     191             :         }
     192             :         else
     193             :         {
     194           0 :             ++f_errcnt;
     195             :             std::cerr
     196             :                 << "error: could not open JSON output file: \""
     197             :                 << filename
     198           0 :                 << "\".\n";
     199           0 :             return;
     200             :         }
     201             :     }
     202             : 
     203           1 :     if(f_verify)
     204             :     {
     205           1 :         verify_output(c);
     206             :     }
     207             : }
     208             : 
     209             : 
     210           1 : void compiler::verify_output(tld_compiler & c)
     211             : {
     212           1 :     tld_file * file(nullptr);
     213           2 :     auto_free_tld_file auto_free(&file);
     214           1 :     tld_file_error err(tld_file_load(f_output.c_str(), &file));
     215           1 :     if(err != TLD_FILE_ERROR_NONE)
     216             :     {
     217           0 :         ++f_errcnt;
     218             :         std::cerr << "error: could not load output file \""
     219             :             << f_output
     220             :             << "\" -- err: "
     221             :             << tld_file_errstr(err)
     222           0 :             << " ("
     223             :             << static_cast<int>(err)
     224           0 :             << ").\n";
     225           0 :         return;
     226             :     }
     227             : 
     228             :     // generate a JSON from what was just loaded
     229             :     // and it has to match the compiler's JSON
     230             :     //
     231           1 :     char * json(tld_file_to_json(file));
     232           1 :     if(json == nullptr)
     233             :     {
     234           0 :         ++f_errcnt;
     235           0 :         std::cerr << "error: conversion of file to JSON failed.\n";
     236           0 :         return;
     237             :     }
     238           2 :     auto_free_string auto_delete(json);
     239             : 
     240             :     // save the verification JSON to a file if we also saved the
     241             :     // JSON of the compiler to a file
     242             :     //
     243           1 :     if(f_output_json)
     244             :     {
     245           2 :         std::string filename;
     246           1 :         std::string::size_type const dot(f_output.rfind('.'));
     247           1 :         if(dot != std::string::npos
     248           1 :         && dot > 0
     249           2 :         && f_output[dot - 1] != '/')
     250             :         {
     251           1 :             filename = f_output.substr(0, dot) + "-verify.json";
     252             :         }
     253             :         else
     254             :         {
     255           0 :             filename = f_output + "-verify.json";
     256             :         }
     257           2 :         std::ofstream out;
     258           1 :         out.open(filename);
     259           1 :         if(out.is_open())
     260             :         {
     261           1 :             out.write(json, strlen(json));
     262             :         }
     263             :         else
     264             :         {
     265           0 :             ++f_errcnt;
     266             :             std::cerr
     267             :                 << "error: could not open JSON output file: \""
     268             :                 << filename
     269           0 :                 << "\".\n";
     270           0 :             return;
     271             :         }
     272             :     }
     273             : 
     274           2 :     std::stringstream compiler_json;
     275           1 :     c.output_to_json(compiler_json, false);
     276             : 
     277           1 :     if(compiler_json.str() != json)
     278             :     {
     279           0 :         ++f_errcnt;
     280             :         std::cerr
     281             :             << "error: compiler & verification JSON differ."
     282           0 :             << (f_output_json
     283             :                 ? " Check the two .json output files to see the differences."
     284             :                 : " Try using the --output-json command line option to get the .json files to find the differences.")
     285           0 :             << "\n";
     286           0 :         return;
     287             :     }
     288             : }
     289             : 
     290             : 
     291             : 
     292             : 
     293           0 : void usage(char * argv0)
     294             : {
     295           0 :     std::string progname(argv0);
     296           0 :     std::string::size_type pos(progname.rfind('/'));
     297           0 :     if(pos != std::string::npos)
     298             :     {
     299           0 :         progname = progname.substr(pos + 1);
     300             :     }
     301           0 :     std::cout << progname << " v" << LIBTLD_VERSION << "\n";
     302           0 :     std::cout << "Usage: " << progname << " [--opts] [<output>]\n";
     303           0 :     std::cout << "Where --opts is one or more of the following:\n";
     304           0 :     std::cout << "    --help | -h             prints out this help screen and exit\n";
     305           0 :     std::cout << "    --c-file                path and filename to the \"tld_data.c\" file\n";
     306           0 :     std::cout << "    --include-offsets       print offset in comment in .json file\n";
     307           0 :     std::cout << "    --output-json           also save to a .json file\n";
     308           0 :     std::cout << "    --source | -s <folder>  define the source (input) folder\n";
     309           0 :     std::cout << "    --verify                verify loading results and compare against sources\n";
     310           0 :     std::cout << "    --version | -V          print out the version and exit\n";
     311           0 :     std::cout << "\n";
     312           0 :     std::cout << "The default source is \"/usr/share/libtld/tlds\".\n";
     313           0 :     std::cout << "The default output is \"/var/lib/libtld/tlds.tld\".\n";
     314           0 :     std::cout << progname << " will not output a C-file or JSON by default.\n";
     315           0 : }
     316             : 
     317             : 
     318           1 : int main(int argc, char * argv[])
     319             : {
     320           2 :     compiler tldc;
     321             : 
     322           7 :     for(int i(1); i < argc; ++i)
     323             :     {
     324           6 :         if(argv[i][0] == '-')
     325             :         {
     326           5 :             if(strcmp(argv[i], "-h") == 0
     327           5 :             || strcmp(argv[i], "--help") == 0)
     328             :             {
     329           0 :                 usage(argv[0]);
     330           0 :                 return 1;
     331             :             }
     332           5 :             else if(strcmp(argv[i], "-V") == 0
     333           5 :                  || strcmp(argv[i], "--version") == 0)
     334             :             {
     335           0 :                 std::cout << LIBTLD_VERSION << std::endl;
     336           0 :                 return 1;
     337             :             }
     338           5 :             else if(strcmp(argv[i], "-s") == 0
     339           5 :                  || strcmp(argv[i], "--source") == 0)
     340             :             {
     341           1 :                 ++i;
     342           2 :                 if(i >= argc)
     343             :                 {
     344           0 :                     tldc.error()
     345           0 :                         << "error: argument missing for --source.\n";
     346             :                 }
     347             :                 else
     348             :                 {
     349           1 :                     tldc.set_input_path(argv[i]);
     350             :                 }
     351             :             }
     352           4 :             else if(strcmp(argv[i], "--verify") == 0)
     353             :             {
     354           1 :                 tldc.set_verify(true);
     355             :             }
     356           3 :             else if(strcmp(argv[i], "--c-file") == 0)
     357             :             {
     358           1 :                 ++i;
     359           1 :                 if(i >= argc)
     360             :                 {
     361           0 :                     tldc.error()
     362           0 :                         << "error: argument missing for --output-c-file.\n";
     363             :                 }
     364             :                 else
     365             :                 {
     366           1 :                     tldc.set_c_file(argv[i]);
     367             :                 }
     368             :             }
     369           2 :             else if(strcmp(argv[i], "--output-json") == 0)
     370             :             {
     371           1 :                 tldc.set_output_json(true);
     372             :             }
     373           1 :             else if(strcmp(argv[i], "--include-offsets") == 0)
     374             :             {
     375           1 :                 tldc.set_include_offsets(true);
     376             :             }
     377             :             else
     378             :             {
     379           0 :                 tldc.error()
     380             :                     << "error: unknown command line option \""
     381           0 :                     << argv[i]
     382           0 :                     << "\".\n";
     383             :             }
     384             :         }
     385             :         else
     386             :         {
     387           1 :             tldc.set_output(argv[i]);
     388             :         }
     389             :     }
     390             : 
     391           1 :     tldc.run();
     392             : 
     393           1 :     return tldc.exit_code();
     394           3 : }
     395             : 
     396             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13