LCOV - code coverage report
Current view: top level - apps - gdal.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 82 83 98.8 %
Date: 2025-06-19 12:30:01 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  CLI front-end
       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             : #include "gdalalgorithm.h"
      14             : #include "commonutils.h"
      15             : #include "cpl_error.h"
      16             : 
      17             : #include "gdal.h"
      18             : 
      19             : #include <cassert>
      20             : #include <utility>
      21             : 
      22             : // #define DEBUG_COMPLETION
      23             : 
      24             : /************************************************************************/
      25             : /*                           EmitCompletion()                           */
      26             : /************************************************************************/
      27             : 
      28             : /** Return on stdout a space-separated list of choices for bash completion */
      29          95 : static void EmitCompletion(std::unique_ptr<GDALAlgorithm> rootAlg,
      30             :                            const std::vector<std::string> &argsIn,
      31             :                            bool lastWordIsComplete)
      32             : {
      33             : #ifdef DEBUG_COMPLETION
      34             :     for (size_t i = 0; i < argsIn.size(); ++i)
      35             :         fprintf(stderr, "arg[%d]='%s'\n", static_cast<int>(i),
      36             :                 argsIn[i].c_str());
      37             : #endif
      38             : 
      39          95 :     std::vector<std::string> args = argsIn;
      40             : 
      41          95 :     std::string ret;
      42       34363 :     const auto addSpace = [&ret]()
      43             :     {
      44       17225 :         if (!ret.empty())
      45       17138 :             ret += " ";
      46       17320 :     };
      47             : 
      48         282 :     if (!args.empty() &&
      49          94 :         (args.back() == "--config" ||
      50         184 :          STARTS_WITH(args.back().c_str(), "--config=") ||
      51         180 :          (args.size() >= 2 && args[args.size() - 2] == "--config")))
      52             :     {
      53           5 :         if (args.back() == "--config=" || args.back().back() != '=')
      54             :         {
      55           6 :             CPLStringList aosConfigOptions(CPLGetKnownConfigOptions());
      56        3192 :             for (const char *pszOpt : cpl::Iterate(aosConfigOptions))
      57             :             {
      58        3189 :                 addSpace();
      59        3189 :                 ret += pszOpt;
      60        3189 :                 ret += '=';
      61             :             }
      62           3 :             printf("%s", ret.c_str());
      63             :         }
      64           5 :         return;
      65             :     }
      66             : 
      67       14126 :     for (const auto &choice : rootAlg->GetAutoComplete(
      68       14126 :              args, lastWordIsComplete, /*showAllOptions = */ true))
      69             :     {
      70       14036 :         addSpace();
      71       14036 :         ret += CPLString(choice).replaceAll(" ", "\\ ");
      72             :     }
      73             : 
      74             : #ifdef DEBUG_COMPLETION
      75             :     fprintf(stderr, "ret = '%s'\n", ret.c_str());
      76             : #endif
      77          90 :     if (!ret.empty())
      78          84 :         printf("%s", ret.c_str());
      79             : }
      80             : 
      81             : /************************************************************************/
      82             : /*                                main()                                */
      83             : /************************************************************************/
      84             : 
      85         149 : MAIN_START(argc, argv)
      86             : {
      87         149 :     const bool bIsCompletion = argc >= 3 && strcmp(argv[1], "completion") == 0;
      88             : 
      89         149 :     if (bIsCompletion)
      90             :     {
      91         190 :         CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
      92          95 :         EarlySetConfigOptions(argc, argv);
      93             :     }
      94             :     else
      95             :     {
      96          54 :         EarlySetConfigOptions(argc, argv);
      97             :     }
      98             : 
      99         149 :     auto alg = GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate(
     100         447 :         GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME);
     101         149 :     assert(alg);
     102             : 
     103             :     // Register GDAL drivers
     104         149 :     GDALAllRegister();
     105             : 
     106         149 :     if (bIsCompletion)
     107             :     {
     108          95 :         const bool bLastWordIsComplete =
     109          95 :             EQUAL(argv[argc - 1], "last_word_is_complete=true");
     110          95 :         if (STARTS_WITH(argv[argc - 1], "last_word_is_complete="))
     111           2 :             --argc;
     112             : 
     113             :         // Process lines like "gdal completion gdal raster last_word_is_complete=true|false"
     114          95 :         EmitCompletion(std::move(alg),
     115         190 :                        std::vector<std::string>(argv + 3, argv + argc),
     116             :                        bLastWordIsComplete);
     117          95 :         return 0;
     118             :     }
     119             : 
     120             :     // Prevent GDALGeneralCmdLineProcessor() to process --format XXX, unless
     121             :     // "gdal" is invoked only with it. Cf #12411
     122         108 :     std::vector<std::pair<char **, char *>> apOrigFormat;
     123          54 :     constexpr const char *pszFormatReplaced = "--format-XXXX";
     124          54 :     if (!(argc == 3 && strcmp(argv[1], "--format") == 0))
     125             :     {
     126         266 :         for (int i = 1; i < argc; ++i)
     127             :         {
     128         213 :             if (strcmp(argv[i], "--format") == 0)
     129             :             {
     130           1 :                 apOrigFormat.emplace_back(argv + i, argv[i]);
     131           1 :                 argv[i] = const_cast<char *>(pszFormatReplaced);
     132             :             }
     133             :         }
     134             :     }
     135             : 
     136             :     // Process generic cmomand options
     137          54 :     argc = GDALGeneralCmdLineProcessor(
     138             :         argc, &argv, GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_MULTIDIM_RASTER);
     139          55 :     for (auto &pair : apOrigFormat)
     140             :     {
     141           1 :         *(pair.first) = pair.second;
     142             :     }
     143             : 
     144          54 :     if (argc < 1)
     145           2 :         return (-argc);
     146             : 
     147         104 :     std::vector<std::string> args;
     148         262 :     for (int i = 1; i < argc; ++i)
     149         419 :         args.push_back(strcmp(argv[i], pszFormatReplaced) == 0 ? "--format"
     150         209 :                                                                : argv[i]);
     151          52 :     CSLDestroy(argv);
     152             : 
     153          52 :     alg->SetCalledFromCommandLine();
     154             : 
     155          52 :     if (!alg->ParseCommandLineArguments(args))
     156             :     {
     157          13 :         if (strstr(CPLGetLastErrorMsg(), "Do you mean") == nullptr &&
     158          10 :             strstr(CPLGetLastErrorMsg(), "Should be one among") == nullptr &&
     159          10 :             strstr(CPLGetLastErrorMsg(), "Potential values for argument") ==
     160          23 :                 nullptr &&
     161           7 :             strstr(CPLGetLastErrorMsg(),
     162             :                    "Single potential value for argument") == nullptr)
     163             :         {
     164           5 :             fprintf(stderr, "%s", alg->GetUsageForCLI(true).c_str());
     165             :         }
     166          13 :         return 1;
     167             :     }
     168             : 
     169             :     {
     170          39 :         const auto stdoutArg = alg->GetActualAlgorithm().GetArg("stdout");
     171          39 :         if (stdoutArg && stdoutArg->GetType() == GAAT_BOOLEAN)
     172           4 :             stdoutArg->Set(true);
     173             :     }
     174             : 
     175             :     GDALProgressFunc pfnProgress =
     176          39 :         alg->IsProgressBarRequested() ? GDALTermProgress : nullptr;
     177          39 :     void *pProgressData = nullptr;
     178             : 
     179          39 :     int ret = 0;
     180          39 :     if (alg->Run(pfnProgress, pProgressData) && alg->Finalize())
     181             :     {
     182             :         const auto outputArg =
     183          38 :             alg->GetActualAlgorithm().GetArg("output-string");
     184          46 :         if (outputArg && outputArg->GetType() == GAAT_STRING &&
     185           8 :             outputArg->IsOutput())
     186             :         {
     187           8 :             printf("%s", outputArg->Get<std::string>().c_str());
     188             :         }
     189             :     }
     190             :     else
     191             :     {
     192           1 :         ret = 1;
     193             :     }
     194             : 
     195          39 :     return ret;
     196             : }
     197             : 
     198           0 : MAIN_END

Generated by: LCOV version 1.14