Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: gdal "main" command 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 "gdalalg_main.h" 14 : 15 : #include "gdal_priv.h" 16 : 17 : #if !defined(_WIN32) 18 : #include <unistd.h> 19 : #endif 20 : 21 : //! @cond Doxygen_Suppress 22 : 23 : #ifndef _ 24 : #define _(x) (x) 25 : #endif 26 : 27 : /************************************************************************/ 28 : /* GDALMainAlgorithm::GDALMainAlgorithm() */ 29 : /************************************************************************/ 30 : 31 489 : GDALMainAlgorithm::GDALMainAlgorithm() 32 489 : : GDALAlgorithm(NAME, DESCRIPTION, HELP_URL) 33 : { 34 3912 : for (const std::string &subAlgName : 35 8313 : GDALGlobalAlgorithmRegistry::GetSingleton().GetNames()) 36 : { 37 : const auto pInfo = 38 3912 : GDALGlobalAlgorithmRegistry::GetSingleton().GetInfo(subAlgName); 39 3912 : if (pInfo) 40 3912 : RegisterSubAlgorithm(*pInfo); 41 : } 42 : 43 978 : SetCallPath({NAME}); 44 : 45 978 : AddArg("version", 0, _("Display GDAL version and exit"), &m_version) 46 489 : .SetHiddenForAPI(); 47 489 : AddArg("drivers", 0, _("Display driver list as JSON document"), &m_drivers); 48 : 49 489 : AddOutputStringArg(&m_output); 50 : 51 : m_longDescription = "'gdal <FILENAME>' can also be used as a shortcut for " 52 : "'gdal info <FILENAME>'.\n" 53 : "And 'gdal read <FILENAME> ! ...' as a shortcut for " 54 489 : "'gdal pipeline <FILENAME> ! ...'."; 55 : 56 489 : SetDisplayInJSONUsage(false); 57 489 : } 58 : 59 : /************************************************************************/ 60 : /* GDALMainAlgorithm::ParseCommandLineArguments() */ 61 : /************************************************************************/ 62 : 63 274 : bool GDALMainAlgorithm::ParseCommandLineArguments( 64 : const std::vector<std::string> &args) 65 : { 66 : // Detect shortest form of pipeline: 67 : // "gdal read in.tif ! .... ! write out.tif" 68 274 : if (args.size() >= 2 && args[0] == "read") 69 : { 70 : m_subAlg = 71 1 : GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate("pipeline"); 72 1 : if (m_subAlg) 73 : { 74 1 : if (IsCalledFromCommandLine()) 75 1 : m_subAlg->SetCalledFromCommandLine(); 76 1 : bool ret = m_subAlg->ParseCommandLineArguments(args); 77 1 : if (ret) 78 : { 79 0 : m_selectedSubAlg = &(m_subAlg->GetActualAlgorithm()); 80 0 : std::vector<std::string> callPath(m_callPath); 81 0 : callPath.push_back("vector"); 82 0 : m_selectedSubAlg->SetCallPath(callPath); 83 0 : return true; 84 : } 85 1 : else if (strstr(CPLGetLastErrorMsg(), 86 1 : "has both raster and vector content")) 87 : { 88 0 : m_showUsage = false; 89 0 : return false; 90 : } 91 : } 92 : 93 1 : return false; 94 : } 95 276 : else if (args.size() == 1 && args[0].size() >= 2 && args[0][0] == '-' && 96 3 : args[0][1] == '-') 97 : { 98 3 : return GDALAlgorithm::ParseCommandLineArguments(args); 99 : } 100 : 101 : // Generic case: "gdal {subcommand} arguments" 102 : // where subcommand is a known subcommand 103 270 : else if (args.size() >= 1) 104 : { 105 269 : const auto nCounter = CPLGetErrorCounter(); 106 269 : if (InstantiateSubAlgorithm(args[0])) 107 265 : return GDALAlgorithm::ParseCommandLineArguments(args); 108 5 : if (CPLGetErrorCounter() == nCounter + 1 && 109 1 : strstr(CPLGetLastErrorMsg(), "Do you mean")) 110 : { 111 1 : return false; 112 : } 113 : } 114 : 115 : // Otherwise check if that is the shortest form of "gdal read mydataset" 116 : // where "read" is omitted: "gdal in.tif" 117 : { 118 : VSIStatBufL sStat; 119 8 : std::vector<char> osResolvedFilename(2048); 120 8 : for (const auto &arg : args) 121 : { 122 6 : if (VSIStatL(arg.c_str(), &sStat) == 0 123 : #if !defined(_WIN32) 124 6 : || readlink(arg.c_str(), osResolvedFilename.data(), 125 : osResolvedFilename.size()) != -1 126 : #endif 127 : ) 128 : { 129 : m_subAlg = 130 4 : GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate( 131 2 : "info"); 132 2 : if (m_subAlg) 133 : { 134 2 : bool ret = m_subAlg->ParseCommandLineArguments(args); 135 2 : if (ret) 136 : { 137 2 : m_selectedSubAlg = &(m_subAlg->GetActualAlgorithm()); 138 2 : std::vector<std::string> callPath(m_callPath); 139 2 : callPath.push_back(m_selectedSubAlg->GetArg("layer") 140 : ? "vector" 141 : : "raster"); 142 2 : m_selectedSubAlg->SetCallPath(callPath); 143 2 : return true; 144 : } 145 0 : else if (strstr(CPLGetLastErrorMsg(), 146 0 : "has both raster and vector content")) 147 : { 148 0 : m_showUsage = false; 149 0 : return false; 150 : } 151 : } 152 : } 153 : } 154 : 155 2 : return GDALAlgorithm::ParseCommandLineArguments(args); 156 : } 157 : } 158 : 159 : /************************************************************************/ 160 : /* GDALMainAlgorithm::GetUsageForCLI() */ 161 : /************************************************************************/ 162 : 163 : std::string 164 24 : GDALMainAlgorithm::GetUsageForCLI(bool shortUsage, 165 : const UsageOptions &usageOptions) const 166 : { 167 24 : if (m_selectedSubAlg) 168 20 : return m_selectedSubAlg->GetUsageForCLI(shortUsage, usageOptions); 169 4 : if (m_showUsage) 170 4 : return GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptions); 171 0 : return std::string(); 172 : } 173 : 174 : /************************************************************************/ 175 : /* GDALMainAlgorithm::RunImpl() */ 176 : /************************************************************************/ 177 : 178 1 : bool GDALMainAlgorithm::RunImpl(GDALProgressFunc, void *) 179 : { 180 1 : if (m_drivers) 181 : { 182 1 : m_output = GDALPrintDriverList(GDAL_OF_KIND_MASK, true); 183 : } 184 1 : return true; 185 : } 186 : 187 : //! @endcond