LCOV - code coverage report
Current view: top level - tools - tldc.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 57.6 % 177 102
Test Date: 2025-07-17 21:03:15 Functions: 76.9 % 13 10
Legend: Lines: hit not hit

            Line data    Source code
       1              : /* TLD tools -- TLD, domain name, and sub-domain extraction
       2              :  * Copyright (c) 2011-2023  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
      25              : //
      26              : #include    <libtld/tld_compiler.h>
      27              : #include    <libtld/tld_file.h>
      28              : 
      29              : 
      30              : // C++
      31              : //
      32              : #include    <fstream>
      33              : #include    <iostream>
      34              : #include    <sstream>
      35              : 
      36              : 
      37              : // C
      38              : //
      39              : #include    <string.h>
      40              : 
      41              : 
      42              : 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            1 :     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            1 :         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            1 :         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            1 :     }
     210              : 
     211            1 :     if(f_verify)
     212              :     {
     213            1 :         verify_output(c);
     214              :     }
     215            1 : }
     216              : 
     217              : 
     218            1 : void compiler::verify_output(tld_compiler & c)
     219              : {
     220            1 :     tld_file * file(nullptr);
     221            1 :     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            0 :             << 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            1 :     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            1 :         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            1 :         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            1 :     }
     281              : 
     282            1 :     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            1 : }
     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            1 :     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            1 :                 if(i >= argc)
     352              :                 {
     353            0 :                     tldc.error()
     354            0 :                         << "error: argument missing for --source.\n";
     355              :                 }
     356              :                 else
     357              :                 {
     358            3 :                     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            3 :                     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            3 :             tldc.set_output(argv[i]);
     401              :         }
     402              :     }
     403              : 
     404            1 :     tldc.run();
     405              : 
     406            1 :     return tldc.exit_code();
     407            1 : }
     408              : 
     409              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions