LCOV - code coverage report
Current view: top level - apps - gdalalg_dispatcher.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 89 95 93.7 %
Date: 2025-01-18 12:42:00 Functions: 7 12 58.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal subcommand dispatcher
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #ifndef GDALALG_DISPATCHER_INCLUDED
      14             : #define GDALALG_DISPATCHER_INCLUDED
      15             : 
      16             : #include "gdalalgorithm.h"
      17             : 
      18             : #include "gdal_priv.h"
      19             : 
      20             : //! @cond Doxygen_Suppress
      21             : 
      22             : /************************************************************************/
      23             : /*                       GDALDispatcherAlgorithm                        */
      24             : /************************************************************************/
      25             : 
      26             : template <class RasterDispatcher, class VectorDispatcher>
      27             : class GDALDispatcherAlgorithm : public GDALAlgorithm
      28             : {
      29             :   public:
      30          36 :     GDALDispatcherAlgorithm(const std::string &name,
      31             :                             const std::string &description,
      32             :                             const std::string &helpURL)
      33             :         : GDALAlgorithm(name, description, helpURL),
      34             :           m_rasterDispatcher(std::make_unique<RasterDispatcher>(
      35           0 :               /* openForMixedRasterVector = */ true)),
      36          36 :           m_vectorDispatcher(std::make_unique<VectorDispatcher>())
      37             :     {
      38             :         // A "info" dispacher command is a shortcut for something like
      39             :         // "raster info", "vector info". Best to expose the latter.
      40          36 :         SetDisplayInJSONUsage(false);
      41          36 :     }
      42             : 
      43             :     bool
      44             :     ParseCommandLineArguments(const std::vector<std::string> &args) override;
      45             : 
      46             :     std::string GetUsageForCLI(bool shortUsage,
      47             :                                const UsageOptions &usageOptions) const override;
      48             : 
      49             :   private:
      50             :     std::unique_ptr<RasterDispatcher> m_rasterDispatcher{};
      51             :     std::unique_ptr<VectorDispatcher> m_vectorDispatcher{};
      52             :     bool m_showUsage = true;
      53             : 
      54           0 :     bool RunImpl(GDALProgressFunc, void *) override
      55             :     {
      56           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      57             :                  "The Run() method should not be called directly on the \"gdal "
      58             :                  "%s\" program.",
      59           0 :                  GetName().c_str());
      60           0 :         return false;
      61             :     }
      62             : };
      63             : 
      64             : /************************************************************************/
      65             : /*         GDALDispatcherAlgorithm::ParseCommandLineArguments()         */
      66             : /************************************************************************/
      67             : 
      68             : template <class RasterDispatcher, class VectorDispatcher>
      69          20 : bool GDALDispatcherAlgorithm<RasterDispatcher, VectorDispatcher>::
      70             :     ParseCommandLineArguments(const std::vector<std::string> &args)
      71             : {
      72             :     // We first try to process with the raster specific algorithm (that has
      73             :     // been instantiated in a special way to accept both raster and vector
      74             :     // input datasets). If the raster specific algorithm can parse successfully
      75             :     // the arguments *and* the dataset is a raster one, then continue processing
      76             :     // with it. Otherwise try with the vector specific algorithm.
      77             : 
      78             :     bool ok;
      79          20 :     if (args.size() > 1)
      80             :     {
      81             :         // Silence errors as it might be rather for the vector algorithm
      82          15 :         CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
      83          15 :         ok = m_rasterDispatcher->ParseCommandLineArguments(args);
      84             :     }
      85             :     else
      86             :     {
      87             :         // If there's just a single argument, we don't need to silence errors
      88             :         // as this will trigger a legitimate error message about the subcommand.
      89           5 :         ok = m_rasterDispatcher->ParseCommandLineArguments(args);
      90             :     }
      91             : 
      92          20 :     if (m_rasterDispatcher->PropagateSpecialActionTo(this))
      93             :     {
      94           0 :         return true;
      95             :     }
      96             : 
      97          20 :     if (ok)
      98             :     {
      99          13 :         auto poDS = m_rasterDispatcher->GetDatasetRef();
     100             :         // cppcheck-suppress knownConditionTrueFalse
     101          26 :         if (poDS &&
     102          13 :             (poDS->GetRasterCount() > 0 || poDS->GetMetadata("SUBDATASETS")))
     103             :         {
     104           7 :             if (poDS->GetLayerCount() != 0)
     105             :             {
     106           2 :                 m_showUsage = false;
     107           4 :                 CPLError(CE_Failure, CPLE_AppDefined,
     108             :                          "'%s' has both raster and vector content. "
     109             :                          "Please use 'gdal raster %s' or 'gdal vector %s'.",
     110           2 :                          poDS->GetDescription(), GetName().c_str(),
     111           2 :                          GetName().c_str());
     112           2 :                 return false;
     113             :             }
     114             : 
     115           5 :             m_selectedSubAlg = m_rasterDispatcher.get();
     116           5 :             std::vector<std::string> callPath(m_callPath);
     117           5 :             callPath.push_back("raster");
     118           5 :             m_selectedSubAlg->SetCallPath(callPath);
     119             : 
     120           5 :             return true;
     121             :         }
     122             :     }
     123           7 :     else if (args.size() <= 1)
     124             :     {
     125           1 :         return false;
     126             :     }
     127             : 
     128          12 :     auto poDSFromRaster = m_rasterDispatcher->GetDatasetRef();
     129             :     // cppcheck-suppress knownConditionTrueFalse
     130          12 :     if (poDSFromRaster)
     131             :     {
     132           6 :         m_vectorDispatcher->SetDataset(poDSFromRaster);
     133             :     }
     134             : 
     135          24 :     std::vector<std::string> argsWithoutInput;
     136          12 :     bool skipNext = false;
     137          46 :     for (const auto &arg : args)
     138             :     {
     139          34 :         if (arg == "-i" || arg == "--input")
     140             :         {
     141           2 :             skipNext = true;
     142             :         }
     143          32 :         else if (!skipNext)
     144             :         {
     145          39 :             if (!STARTS_WITH(arg.c_str(), "--input=") &&
     146           9 :                 !(poDSFromRaster && arg == poDSFromRaster->GetDescription()))
     147             :             {
     148          26 :                 argsWithoutInput.push_back(arg);
     149             :             }
     150             :         }
     151             :         else
     152             :         {
     153           2 :             skipNext = false;
     154             :         }
     155             :     }
     156             : 
     157             :     {
     158          12 :         CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
     159          12 :         ok = m_vectorDispatcher->ParseCommandLineArguments(argsWithoutInput);
     160             :     }
     161          12 :     if (ok)
     162             :     {
     163           8 :         m_selectedSubAlg = m_vectorDispatcher.get();
     164           8 :         std::vector<std::string> callPath(m_callPath);
     165           8 :         callPath.push_back("vector");
     166           8 :         m_selectedSubAlg->SetCallPath(callPath);
     167             : 
     168           8 :         return true;
     169             :     }
     170             : 
     171           4 :     bool ret = false;
     172          10 :     for (const auto &arg : args)
     173             :     {
     174             :         VSIStatBufL sStat;
     175          10 :         if (VSIStatL(arg.c_str(), &sStat) == 0)
     176             :         {
     177           4 :             auto poDS =
     178             :                 std::unique_ptr<GDALDataset>(GDALDataset::Open(arg.c_str()));
     179           4 :             if (poDS)
     180             :             {
     181           5 :                 if (poDS->GetRasterCount() > 0 ||
     182           1 :                     poDS->GetMetadata("SUBDATASETS"))
     183             :                 {
     184           3 :                     if (poDS->GetLayerCount() != 0)
     185             :                     {
     186           1 :                         m_showUsage = false;
     187           3 :                         CPLError(CE_Failure, CPLE_AppDefined,
     188             :                                  "'%s' has both raster and vector content. "
     189             :                                  "Please use 'gdal raster %s' or 'gdal "
     190             :                                  "vector %s'.",
     191           2 :                                  poDS->GetDescription(), GetName().c_str(),
     192           1 :                                  GetName().c_str());
     193           1 :                         return false;
     194             :                     }
     195           2 :                     m_rasterDispatcher = std::make_unique<RasterDispatcher>();
     196           2 :                     auto poDSRaw = poDS.get();
     197           2 :                     m_rasterDispatcher->SetDataset(poDS.release());
     198           2 :                     poDSRaw->Release();
     199           2 :                     m_selectedSubAlg = m_rasterDispatcher.get();
     200           4 :                     std::vector<std::string> callPath(m_callPath);
     201           2 :                     callPath.push_back("raster");
     202           2 :                     m_selectedSubAlg->SetCallPath(callPath);
     203           2 :                     ret = m_selectedSubAlg->ParseCommandLineArguments(
     204             :                         argsWithoutInput);
     205           2 :                     break;
     206             :                 }
     207           1 :                 else if (poDS->GetLayerCount() != 0)
     208             :                 {
     209           1 :                     m_vectorDispatcher = std::make_unique<VectorDispatcher>();
     210           1 :                     auto poDSRaw = poDS.get();
     211           1 :                     m_vectorDispatcher->SetDataset(poDS.release());
     212           1 :                     poDSRaw->Release();
     213           1 :                     m_selectedSubAlg = m_vectorDispatcher.get();
     214           2 :                     std::vector<std::string> callPath(m_callPath);
     215           1 :                     callPath.push_back("vector");
     216           1 :                     m_selectedSubAlg->SetCallPath(callPath);
     217           1 :                     ret = m_selectedSubAlg->ParseCommandLineArguments(
     218             :                         argsWithoutInput);
     219           1 :                     break;
     220             :                 }
     221             :             }
     222             :         }
     223             :     }
     224             : 
     225           3 :     return ret;
     226             : }
     227             : 
     228             : /************************************************************************/
     229             : /*                 GDALDispatcherAlgorithm::GetUsageForCLI()            */
     230             : /************************************************************************/
     231             : 
     232             : template <class RasterDispatcher, class VectorDispatcher>
     233             : std::string
     234           3 : GDALDispatcherAlgorithm<RasterDispatcher, VectorDispatcher>::GetUsageForCLI(
     235             :     bool shortUsage, const UsageOptions &usageOptions) const
     236             : {
     237           3 :     if (m_selectedSubAlg)
     238             :     {
     239           1 :         return m_selectedSubAlg->GetUsageForCLI(shortUsage, usageOptions);
     240             :     }
     241           2 :     if (m_showUsage)
     242             :     {
     243           1 :         return GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptions);
     244             :     }
     245           1 :     return std::string();
     246             : }
     247             : 
     248             : //! @endcond
     249             : 
     250             : #endif  // GDALALG_DISPATCHER_INCLUDED

Generated by: LCOV version 1.14