LCOV - code coverage report
Current view: top level - source/app - application.cpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 88.3 % 162 143
Test Date: 2026-08-30 22:23:37 Functions: 85.0 % 20 17

            Line data    Source code
       1              : /** \file application.cpp
       2              :  * \author Jared R. Males
       3              :  * \brief Implementation of a class for managing applications
       4              :  *
       5              :  */
       6              : 
       7              : //***********************************************************************//
       8              : // Copyright 2021 Jared R. Males (jaredmales@gmail.com)
       9              : //
      10              : // This file is part of mxlib.
      11              : //
      12              : // mxlib is free software: you can redistribute it and/or modify
      13              : // it under the terms of the GNU General Public License as published by
      14              : // the Free Software Foundation, either version 3 of the License, or
      15              : // (at your option) any later version.
      16              : //
      17              : // mxlib is distributed in the hope that it will be useful,
      18              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      19              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20              : // GNU General Public License for more details.
      21              : //
      22              : // You should have received a copy of the GNU General Public License
      23              : // along with mxlib.  If not, see <http://www.gnu.org/licenses/>.
      24              : //***********************************************************************//
      25              : 
      26              : #include "app/application.hpp"
      27              : #include "sys/environment.hpp"
      28              : 
      29              : namespace mx
      30              : {
      31              : namespace app
      32              : {
      33              : 
      34            9 : application::~application()
      35              : {
      36            9 :     return;
      37            9 : }
      38              : 
      39            8 : int application::main( int argc, char **argv )
      40              : {
      41            8 :     m_argc = argc;
      42            8 :     m_argv = argv;
      43              : 
      44            8 :     setup( argc, argv );
      45              : 
      46            8 :     if(m_configOnly)
      47              :     {
      48            1 :         return 1;
      49              :     }
      50              : 
      51            7 :     if( doHelp )
      52              :     {
      53            3 :         help();
      54            3 :         return 1;
      55              :     }
      56              : 
      57            4 :     if( !m_preserveConfig )
      58              :     {
      59            2 :         config.clear();
      60              :     }
      61              : 
      62            4 :     return execute();
      63              : }
      64              : 
      65            2 : void application::setConfigPathGlobal( const std::string &s )
      66              : {
      67            2 :     m_configPathGlobal = s;
      68            2 : }
      69              : 
      70            1 : void application::setConfigPathUser( const std::string &s )
      71              : {
      72            1 :     m_configPathUser = s;
      73            1 : }
      74              : 
      75            1 : void application::setConfigPathLocal( const std::string &s )
      76              : {
      77            1 :     m_configPathLocal = s;
      78            1 : }
      79              : 
      80            0 : void application::setupConfig() // virtual
      81              : {
      82            0 :     return;
      83              : }
      84              : 
      85            0 : void application::loadConfig() // virtual
      86              : {
      87            0 :     return;
      88              : }
      89              : 
      90            0 : int application::execute() // virtual
      91              : {
      92            0 :     return 0;
      93              : }
      94              : 
      95            8 : void application::setup( int argc, char **argv )
      96              : {
      97            8 :     invokedName = argv[0];
      98              : 
      99            8 :     setupStandardConfig();
     100            8 :     setupStandardHelp();
     101            8 :     setupBasicConfig();
     102            8 :     setupConfig();
     103              : 
     104            8 :     setDefaults( argc, argv );
     105              : 
     106              :     //------------------------------------
     107              :     // First check if help is requested.
     108              :     // This short circuits everything else
     109              :     //------------------------------------
     110           16 :     config.parseCommandLine( argc, argv, "help" );
     111              : 
     112            8 :     loadStandardHelp();
     113              : 
     114            8 :     if(doHelp)
     115              :     {
     116            2 :         return;
     117              :     }
     118              : 
     119              :     //------------------------------------
     120              :     // Now start reading config files
     121              :     //------------------------------------
     122            6 :     if((config.readConfig( m_configPathGlobal, m_requireConfigPathGlobal ) < 0) && m_requireConfigPathGlobal)
     123              :     {
     124            1 :         doHelp = true;
     125            1 :         return;
     126              :     }
     127              : 
     128            5 :     if((config.readConfig( m_configPathUser, m_requireConfigPathUser ) < 0) && m_requireConfigPathUser)
     129              :     {
     130            0 :         doHelp = true;
     131            0 :         return;
     132              :     }
     133              : 
     134            5 :     if((config.readConfig( m_configPathLocal, m_requireConfigPathLocal ) < 0) && m_requireConfigPathLocal)
     135              :     {
     136            0 :         doHelp = true;
     137            0 :         return;
     138              :     }
     139              : 
     140              :     // Parse CL just to get the CL config.
     141           10 :     config.parseCommandLine( argc, argv, "config" );
     142              : 
     143              :     // And now get the value of it and parse it.
     144            5 :     loadStandardConfig();
     145            5 :     config.readConfig( m_configPathCL );
     146              : 
     147              :     // Now parse the command line for real.
     148           10 :     config.parseCommandLine( argc, argv );
     149              : 
     150            5 :     loadStandardHelp(); //Check one more time, could have been config-filed
     151              : 
     152            5 :     if(doHelp)
     153              :     {
     154            0 :         return;
     155              :     }
     156              : 
     157            5 :     loadBasicConfig();
     158            5 :     loadConfig();
     159              : 
     160            5 :     checkConfig();
     161              : }
     162              : 
     163            1 : int application::reReadConfig()
     164              : {
     165            1 :     config.readConfig( m_configPathGlobal );
     166            1 :     config.readConfig( m_configPathUser );
     167            1 :     config.readConfig( m_configPathLocal );
     168              : 
     169            1 :     config.readConfig( m_configPathCL );
     170              : 
     171              :     // Now parse the command line for real.
     172            2 :     config.parseCommandLine( m_argc, m_argv );
     173              : 
     174            1 :     return 0;
     175              : }
     176              : 
     177            9 : void application::setDefaults( int argc, char **argv )
     178              : {
     179              :     static_cast<void>( argc );
     180              :     static_cast<void>( argv );
     181              : 
     182            9 :     std::string tmp;
     183              : 
     184            9 :     if( m_configPathGlobal_env != "" )
     185              :     {
     186            1 :         m_configPathGlobal = sys::getEnv( m_configPathGlobal_env );
     187              :     }
     188              : 
     189            9 :     if( m_configPathUser_env != "" )
     190              :     {
     191            1 :         m_configPathUser = sys::getEnv( m_configPathUser_env );
     192              :     }
     193              : 
     194            9 :     if( m_configPathUser != "" )
     195              :     {
     196              :         // If it's a relative path, add it to the HOME directory
     197            1 :         if( m_configPathUser[0] != '/' && m_configPathUser[0] != '~' )
     198              :         {
     199            0 :             tmp = sys::getEnv( "HOME" );
     200            0 :             tmp += "/" + m_configPathUser;
     201            0 :             m_configPathUser = tmp;
     202              :         }
     203              :     }
     204              : 
     205            9 :     if( m_configPathLocal_env != "" )
     206              :     {
     207            1 :         std::string cpl = sys::getEnv( m_configPathLocal_env.c_str() );
     208            1 :         if(cpl.size() > 0)
     209              :         {
     210            1 :             m_configPathLocal = cpl;
     211            1 :             if( m_configPathLocal.back() != '/' )
     212              :             {
     213            1 :                 m_configPathLocal += '/';
     214              :             }
     215              :         }
     216            1 :     }
     217              : 
     218            9 :     if( m_configPathCLBase_env != "" )
     219              :     {
     220            1 :         std::string cpclbase = sys::getEnv( m_configPathCLBase_env.c_str() );
     221              : 
     222            1 :         if( cpclbase.size() > 0 )
     223              :         {
     224            1 :             m_configPathCLBase = cpclbase;
     225            1 :             if( m_configPathCLBase.back() != '/' )
     226              :             {
     227            1 :                 m_configPathCLBase += '/';
     228              :             }
     229              :         }
     230            1 :     }
     231              : 
     232           18 :     return;
     233            9 : }
     234              : 
     235            8 : void application::setupStandardConfig() // virtual
     236              : {
     237          112 :     config.add( "config", "c", "config", argType::Required, "", "config", false, "string", "A local config file" );
     238            8 : }
     239              : 
     240            8 : void application::setupStandardHelp() // virtual
     241              : {
     242          112 :     config.add( "help", "h", "help", argType::True, "", "", false, "none", "Print this message and exit" );
     243            8 : }
     244              : 
     245            5 : void application::loadStandardConfig() // virtual
     246              : {
     247           10 :     config( m_configPathCL, "config" );
     248            5 :     m_configPathCL = m_configPathCLBase + m_configPathCL;
     249            5 : }
     250              : 
     251           13 : void application::loadStandardHelp() // virtual
     252              : {
     253           26 :     config( doHelp, "help" );
     254           13 : }
     255              : 
     256            8 : void application::setupBasicConfig() // virtual
     257              : {
     258            8 :     return;
     259              : }
     260              : 
     261            5 : void application::loadBasicConfig() // virtual
     262              : {
     263            5 :     return;
     264              : }
     265              : 
     266            5 : void application::checkConfig() // virtual
     267              : {
     268            5 :     return;
     269              : }
     270              : 
     271            3 : void application::optionHelp( configTarget &tgt,
     272              :                               ioutils::textTable &tt ) // virtual
     273              : {
     274            3 :     std::string tmp;
     275            3 :     int row = tgt.orderAdded;
     276              : 
     277            3 :     if( tgt.shortOpt != "" )
     278              :     {
     279            3 :         tmp = "-" + tgt.shortOpt;
     280            3 :         tt.addCell( row, 0, tmp );
     281              :     }
     282              : 
     283            3 :     if( tgt.longOpt != "" )
     284              :     {
     285            3 :         tmp = "--" + tgt.longOpt;
     286            3 :         tt.addCell( row, 1, tmp );
     287              :     }
     288              : 
     289            3 :     tmp = "";
     290            3 :     if( tgt.section != "" )
     291              :     {
     292            1 :         tmp = tgt.section + ".";
     293              :     }
     294              : 
     295            3 :     if( tgt.keyword != "" )
     296              :     {
     297            2 :         tmp += tgt.keyword;
     298            2 :         tt.addCell( row, 2, tmp );
     299              :     }
     300              : 
     301            3 :     if( tgt.helpType != "" )
     302              :     {
     303            3 :         tmp = "<" + tgt.helpType + "> ";
     304            3 :         tt.addCell( row, 3, tmp );
     305              :     }
     306              : 
     307            3 :     tt.addCell( row, 4, tgt.helpExplanation );
     308            3 : }
     309              : 
     310            1 : void application::help() // virtual
     311              : {
     312            1 :     appConfigurator::targetIterator targIt;
     313            1 :     appConfigurator::clOnlyTargetIterator clOnlyTargIt;
     314              : 
     315            1 :     ioutils::textTable tt;
     316              : 
     317            1 :     int otherColWidth = m_helpSOColWidth + m_helpLOColWidth + m_helpCFColWidth + m_helpTypeColWidth;
     318              : 
     319              :     tt.m_colWidths = {
     320            1 :         m_helpSOColWidth, m_helpLOColWidth, m_helpCFColWidth, m_helpTypeColWidth, m_helpWidth - otherColWidth - 4 - 4 };
     321            1 :     tt.m_lineStart = "    ";
     322            1 :     tt.m_colSep = " ";
     323            1 :     tt.m_rowSep = "";
     324              : 
     325            1 :     std::cerr << "usage: " << invokedName << " [options] " << m_nonOptionHelp << "\n";
     326            1 :     std::cerr << "\n";
     327            1 :     std::cerr << "  Required arguments:\n";
     328              : 
     329            1 :     for( clOnlyTargIt = config.clOnlyTargets.begin(); clOnlyTargIt != config.clOnlyTargets.end(); ++clOnlyTargIt )
     330              :     {
     331            0 :         if( clOnlyTargIt->isRequired == true )
     332              :         {
     333            0 :             optionHelp( *clOnlyTargIt, tt );
     334              :         }
     335              :     }
     336              : 
     337            4 :     for( targIt = config.m_targets.begin(); targIt != config.m_targets.end(); ++targIt )
     338              :     {
     339            3 :         if( targIt->second.isRequired == true )
     340              :         {
     341            0 :             optionHelp( targIt->second, tt );
     342              :         }
     343              :     }
     344              : 
     345            1 :     tt.outPut( std::cerr );
     346            1 :     tt.m_rows.clear();
     347              : 
     348              :     // row = 0;
     349            1 :     std::cerr << "\n  Optional arguments:\n";
     350              : 
     351            1 :     for( clOnlyTargIt = config.clOnlyTargets.begin(); clOnlyTargIt != config.clOnlyTargets.end(); ++clOnlyTargIt )
     352              :     {
     353            0 :         if( clOnlyTargIt->isRequired == false )
     354              :         {
     355            0 :             optionHelp( *clOnlyTargIt, tt );
     356              :         }
     357              :     }
     358              : 
     359            4 :     for( targIt = config.m_targets.begin(); targIt != config.m_targets.end(); ++targIt )
     360              :     {
     361            3 :         if( targIt->second.isRequired == false )
     362              :         {
     363            3 :             optionHelp( targIt->second, tt );
     364              :         }
     365              :     }
     366              : 
     367            1 :     tt.outPut( std::cerr );
     368            1 : }
     369              : 
     370              : } // namespace app
     371              : } // namespace mx
        

Generated by: LCOV version 2.0-1