LCOV - code coverage report
Current view: top level - tools - tldc.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 99 173 57.2 %
Date: 2022-11-01 12:46:13 Functions: 14 17 82.4 %
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             :     void            set_verbose(bool verbose);
      54             : 
      55             :     void            run();
      56             : 
      57             : private:
      58             :     void            verify_output(tld_compiler & c);
      59             : 
      60             :     int             f_errcnt = 0;
      61             :     std::string     f_input_path = std::string();
      62             :     std::string     f_output = std::string();
      63             :     std::string     f_c_file = std::string();
      64             :     bool            f_verify = false;
      65             :     bool            f_output_json = false;
      66             :     bool            f_include_offsets = false;
      67             :     bool            f_verbose = false;
      68             : };
      69             : 
      70             : 
      71           0 : std::ostream & compiler::error()
      72             : {
      73           0 :     ++f_errcnt;
      74           0 :     return std::cerr;
      75             : }
      76             : 
      77             : 
      78           1 : int compiler::exit_code() const
      79             : {
      80           1 :     return f_errcnt == 0 ? 0 : 1;
      81             : }
      82             : 
      83             : 
      84           1 : void compiler::set_input_path(std::string const & path)
      85             : {
      86           1 :     f_input_path = path;
      87           1 : }
      88             : 
      89             : 
      90           1 : void compiler::set_output(std::string const & output)
      91             : {
      92           1 :     f_output = output;
      93           1 : }
      94             : 
      95             : 
      96           1 : void compiler::set_c_file(std::string const & c_file)
      97             : {
      98           1 :     f_c_file = c_file;
      99           1 : }
     100             : 
     101             : 
     102           1 : void compiler::set_verify(bool verify)
     103             : {
     104           1 :     f_verify = verify;
     105           1 : }
     106             : 
     107             : 
     108           1 : void compiler::set_output_json(bool output_json)
     109             : {
     110           1 :     f_output_json = output_json;
     111           1 : }
     112             : 
     113             : 
     114           1 : void compiler::set_include_offsets(bool include_offsets)
     115             : {
     116           1 :     f_include_offsets = include_offsets;
     117           1 : }
     118             : 
     119             : 
     120           0 : void compiler::set_verbose(bool verbose)
     121             : {
     122           0 :     f_verbose = verbose;
     123           0 : }
     124             : 
     125             : 
     126           1 : void compiler::run()
     127             : {
     128           1 :     if(f_errcnt != 0)
     129             :     {
     130             :         // command line found errors, return immediately
     131           0 :         return;
     132             :     }
     133             : 
     134           1 :     if(f_input_path.empty())
     135             :     {
     136           0 :         ++f_errcnt;
     137           0 :         std::cerr << "error: an input path is required.\n";
     138           0 :         return;
     139             :     }
     140             : 
     141           1 :     if(f_output.empty())
     142             :     {
     143           0 :         ++f_errcnt;
     144           0 :         std::cerr << "error: an output filename is required.\n";
     145           0 :         return;
     146             :     }
     147             : 
     148           1 :     std::cout << "Compiling TLDs from \"" << f_input_path << "\"..." << std::endl;
     149             : 
     150           2 :     tld_compiler c;
     151           1 :     c.set_input_folder(f_input_path);
     152           1 :     c.set_output(f_output);
     153           1 :     c.set_c_file(f_c_file);
     154           1 :     if(!c.compile())
     155             :     {
     156           0 :         ++f_errcnt;
     157             :         std::cerr
     158             :             << "error:"
     159           0 :             << c.get_filename()
     160           0 :             << ":"
     161             :             << c.get_line()
     162             :             << ": "
     163           0 :             << c.get_errmsg()
     164           0 :             << " (errno: "
     165             :             << c.get_errno()
     166             :             << ", "
     167           0 :             << strerror(c.get_errno())
     168           0 :             << ")\n";
     169           0 :         return;
     170             :     }
     171             : 
     172           1 :     std::cout << "Number of strings:        " << c.get_string_manager().size()         << "\n";
     173           1 :     std::cout << "Longest string:           " << c.get_string_manager().max_length()   << "\n";
     174           1 :     std::cout << "Total string length:      " << c.get_string_manager().total_length() << "\n";
     175           1 :     std::cout << "Included strings:         " << c.get_string_manager().included_count() << " (saved length: " << c.get_string_manager().included_length() << ")\n";
     176           1 :     std::cout << "Mergeable strings:        " << c.get_string_manager().merged_count() << " (saved length: " << c.get_string_manager().merged_length() << ")\n";
     177           1 :     std::cout << "Compressed string length: " << c.get_string_manager().compressed_length() << std::endl;
     178             :     // TODO: add info about tags
     179             : 
     180           1 :     if(f_output_json)
     181             :     {
     182           2 :         std::string filename;
     183           1 :         std::string::size_type const dot(f_output.rfind('.'));
     184           1 :         if(dot != std::string::npos
     185           1 :         && dot > 0
     186           2 :         && f_output[dot - 1] != '/')
     187             :         {
     188           1 :             filename = f_output.substr(0, dot) + ".json";
     189             :         }
     190             :         else
     191             :         {
     192           0 :             filename = f_output + ".json";
     193             :         }
     194           2 :         std::ofstream out;
     195           1 :         out.open(filename);
     196           1 :         if(out.is_open())
     197             :         {
     198           1 :             c.output_to_json(out, f_include_offsets);
     199             :         }
     200             :         else
     201             :         {
     202           0 :             ++f_errcnt;
     203             :             std::cerr
     204             :                 << "error: could not open JSON output file: \""
     205             :                 << filename
     206           0 :                 << "\".\n";
     207           0 :             return;
     208             :         }
     209             :     }
     210             : 
     211           1 :     if(f_verify)
     212             :     {
     213           1 :         verify_output(c);
     214             :     }
     215             : }
     216             : 
     217             : 
     218           1 : void compiler::verify_output(tld_compiler & c)
     219             : {
     220           1 :     tld_file * file(nullptr);
     221           2 :     auto_free_tld_file auto_free(&file);
     222           1 :     tld_file_error err(tld_file_load(f_output.c_str(), &file));
     223           1 :     if(err != TLD_FILE_ERROR_NONE)
     224             :     {
     225           0 :         ++f_errcnt;
     226             :         std::cerr << "error: could not load output file \""
     227             :             << f_output
     228             :             << "\" -- err: "
     229             :             << tld_file_errstr(err)
     230           0 :             << " ("
     231             :             << static_cast<int>(err)
     232           0 :             << ").\n";
     233           0 :         return;
     234             :     }
     235             : 
     236             :     // generate a JSON from what was just loaded
     237             :     // and it has to match the compiler's JSON
     238             :     //
     239           1 :     char * json(tld_file_to_json(file));
     240           1 :     if(json == nullptr)
     241             :     {
     242           0 :         ++f_errcnt;
     243           0 :         std::cerr << "error: conversion of file to JSON failed.\n";
     244           0 :         return;
     245             :     }
     246           2 :     auto_free_string auto_delete(json);
     247             : 
     248             :     // save the verification JSON to a file if we also saved the
     249             :     // JSON of the compiler to a file
     250             :     //
     251           1 :     if(f_output_json)
     252             :     {
     253           2 :         std::string filename;
     254           1 :         std::string::size_type const dot(f_output.rfind('.'));
     255           1 :         if(dot != std::string::npos
     256           1 :         && dot > 0
     257           2 :         && f_output[dot - 1] != '/')
     258             :         {
     259           1 :             filename = f_output.substr(0, dot) + "-verify.json";
     260             :         }
     261             :         else
     262             :         {
     263           0 :             filename = f_output + "-verify.json";
     264             :         }
     265           2 :         std::ofstream out;
     266           1 :         out.open(filename);
     267           1 :         if(out.is_open())
     268             :         {
     269           1 :             out.write(json, strlen(json));
     270             :         }
     271             :         else
     272             :         {
     273           0 :             ++f_errcnt;
     274             :             std::cerr
     275             :                 << "error: could not open JSON output file: \""
     276             :                 << filename
     277           0 :                 << "\".\n";
     278           0 :             return;
     279             :         }
     280             :     }
     281             : 
     282           2 :     std::stringstream compiler_json;
     283           1 :     c.output_to_json(compiler_json, false);
     284             : 
     285           1 :     if(compiler_json.str() != json)
     286             :     {
     287           0 :         ++f_errcnt;
     288             :         std::cerr
     289             :             << "error: compiler & verification JSON differ."
     290           0 :             << (f_output_json
     291             :                 ? " Check the two .json output files to see the differences."
     292             :                 : " Try using the --output-json command line option to get the .json files to find the differences.")
     293           0 :             << "\n";
     294           0 :         return;
     295             :     }
     296             : }
     297             : 
     298             : 
     299             : 
     300             : 
     301           0 : void usage(char * argv0)
     302             : {
     303           0 :     std::string progname(argv0);
     304           0 :     std::string::size_type pos(progname.rfind('/'));
     305           0 :     if(pos != std::string::npos)
     306             :     {
     307           0 :         progname = progname.substr(pos + 1);
     308             :     }
     309           0 :     std::cout << progname << " v" << LIBTLD_VERSION << "\n";
     310           0 :     std::cout << "Usage: " << progname << " [--opts] [<output>]\n";
     311           0 :     std::cout << "Where --opts is one or more of the following:\n";
     312           0 :     std::cout << "    --help | -h             prints out this help screen and exit\n";
     313           0 :     std::cout << "    --c-file                path and filename to the \"tld_data.c\" file\n";
     314           0 :     std::cout << "    --include-offsets       print offset in comment in .json file\n";
     315           0 :     std::cout << "    --output-json           also save to a .json file\n";
     316           0 :     std::cout << "    --source | -s <folder>  define the source (input) folder\n";
     317           0 :     std::cout << "    --verify                verify loading results and compare against sources\n";
     318           0 :     std::cout << "    --verbose               print out more information about what is happening\n";
     319           0 :     std::cout << "    --version | -V          print out the version and exit\n";
     320           0 :     std::cout << "\n";
     321           0 :     std::cout << "The default source is \"/usr/share/libtld/tlds\".\n";
     322           0 :     std::cout << "The default output is \"/var/lib/libtld/tlds.tld\".\n";
     323           0 :     std::cout << progname << " will not output a C-file or JSON by default.\n";
     324           0 : }
     325             : 
     326             : 
     327           1 : int main(int argc, char * argv[])
     328             : {
     329           2 :     compiler tldc;
     330             : 
     331           7 :     for(int i(1); i < argc; ++i)
     332             :     {
     333           6 :         if(argv[i][0] == '-')
     334             :         {
     335           5 :             if(strcmp(argv[i], "-h") == 0
     336           5 :             || strcmp(argv[i], "--help") == 0)
     337             :             {
     338           0 :                 usage(argv[0]);
     339           0 :                 return 1;
     340             :             }
     341           5 :             else if(strcmp(argv[i], "-V") == 0
     342           5 :                  || strcmp(argv[i], "--version") == 0)
     343             :             {
     344           0 :                 std::cout << LIBTLD_VERSION << std::endl;
     345           0 :                 return 1;
     346             :             }
     347           5 :             else if(strcmp(argv[i], "-s") == 0
     348           5 :                  || strcmp(argv[i], "--source") == 0)
     349             :             {
     350           1 :                 ++i;
     351           2 :                 if(i >= argc)
     352             :                 {
     353           0 :                     tldc.error()
     354           0 :                         << "error: argument missing for --source.\n";
     355             :                 }
     356             :                 else
     357             :                 {
     358           1 :                     tldc.set_input_path(argv[i]);
     359             :                 }
     360             :             }
     361           4 :             else if(strcmp(argv[i], "--verify") == 0)
     362             :             {
     363           1 :                 tldc.set_verify(true);
     364             :             }
     365           3 :             else if(strcmp(argv[i], "--c-file") == 0)
     366             :             {
     367           1 :                 ++i;
     368           1 :                 if(i >= argc)
     369             :                 {
     370           0 :                     tldc.error()
     371           0 :                         << "error: argument missing for --output-c-file.\n";
     372             :                 }
     373             :                 else
     374             :                 {
     375           1 :                     tldc.set_c_file(argv[i]);
     376             :                 }
     377             :             }
     378           2 :             else if(strcmp(argv[i], "--output-json") == 0)
     379             :             {
     380           1 :                 tldc.set_output_json(true);
     381             :             }
     382           1 :             else if(strcmp(argv[i], "--include-offsets") == 0)
     383             :             {
     384           1 :                 tldc.set_include_offsets(true);
     385             :             }
     386           0 :             else if(strcmp(argv[i], "--verbose") == 0)
     387             :             {
     388           0 :                 tldc.set_verbose(true);
     389             :             }
     390             :             else
     391             :             {
     392           0 :                 tldc.error()
     393             :                     << "error: unknown command line option \""
     394           0 :                     << argv[i]
     395           0 :                     << "\".\n";
     396             :             }
     397             :         }
     398             :         else
     399             :         {
     400           1 :             tldc.set_output(argv[i]);
     401             :         }
     402             :     }
     403             : 
     404           1 :     tldc.run();
     405             : 
     406           1 :     return tldc.exit_code();
     407           3 : }
     408             : 
     409             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13