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 : 16 : #include "gdal.h" 17 : 18 : #include <cassert> 19 : 20 : // #define DEBUG_COMPLETION 21 : 22 : /************************************************************************/ 23 : /* EmitCompletion() */ 24 : /************************************************************************/ 25 : 26 : /** Return on stdout a space-separated list of choices for bash completion */ 27 57 : static void EmitCompletion(std::unique_ptr<GDALAlgorithm> rootAlg, 28 : const std::vector<std::string> &argsIn) 29 : { 30 : #ifdef DEBUG_COMPLETION 31 : for (size_t i = 0; i < argsIn.size(); ++i) 32 : fprintf(stderr, "arg[%d]='%s'\n", static_cast<int>(i), 33 : argsIn[i].c_str()); 34 : #endif 35 : 36 57 : std::vector<std::string> args = argsIn; 37 : 38 57 : std::string ret; 39 32069 : const auto addSpace = [&ret]() 40 : { 41 16061 : if (!ret.empty()) 42 16008 : ret += " "; 43 16118 : }; 44 : 45 168 : if (!args.empty() && 46 56 : (args.back() == "--config" || 47 108 : STARTS_WITH(args.back().c_str(), "--config=") || 48 104 : (args.size() >= 2 && args[args.size() - 2] == "--config"))) 49 : { 50 4 : if (args.back() == "--config=" || args.back().back() != '=') 51 : { 52 4 : CPLStringList aosConfigOptions(CPLGetKnownConfigOptions()); 53 2120 : for (const char *pszOpt : cpl::Iterate(aosConfigOptions)) 54 : { 55 2118 : addSpace(); 56 2118 : ret += pszOpt; 57 2118 : ret += '='; 58 : } 59 2 : printf("%s", ret.c_str()); 60 : } 61 4 : return; 62 : } 63 : 64 : // Get inner-most algorithm 65 53 : bool showAllOptions = true; 66 106 : auto curAlg = std::move(rootAlg); 67 154 : while (!args.empty() && !args.front().empty() && args.front()[0] != '-') 68 : { 69 127 : auto subAlg = curAlg->InstantiateSubAlgorithm(args.front()); 70 127 : if (!subAlg) 71 26 : break; 72 101 : showAllOptions = false; 73 101 : args.erase(args.begin()); 74 101 : curAlg = std::move(subAlg); 75 : } 76 : 77 13996 : for (const auto &choice : curAlg->GetAutoComplete(args, showAllOptions)) 78 : { 79 13943 : addSpace(); 80 13943 : ret += CPLString(choice).replaceAll(" ", "\\ "); 81 : } 82 : 83 : #ifdef DEBUG_COMPLETION 84 : fprintf(stderr, "ret = '%s'\n", ret.c_str()); 85 : #endif 86 53 : if (!ret.empty()) 87 51 : printf("%s", ret.c_str()); 88 : } 89 : 90 : /************************************************************************/ 91 : /* main() */ 92 : /************************************************************************/ 93 : 94 73 : MAIN_START(argc, argv) 95 : { 96 73 : auto alg = GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate( 97 219 : GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME); 98 73 : assert(alg); 99 : 100 73 : if (argc >= 3 && strcmp(argv[1], "completion") == 0) 101 : { 102 57 : GDALAllRegister(); 103 : 104 : // Process lines like "gdal completion gdal raster" 105 57 : EmitCompletion(std::move(alg), 106 114 : std::vector<std::string>(argv + 3, argv + argc)); 107 57 : return 0; 108 : } 109 : 110 16 : EarlySetConfigOptions(argc, argv); 111 : 112 : /* -------------------------------------------------------------------- */ 113 : /* Register standard GDAL drivers, and process generic GDAL */ 114 : /* command options. */ 115 : /* -------------------------------------------------------------------- */ 116 : 117 16 : GDALAllRegister(); 118 : 119 16 : argc = GDALGeneralCmdLineProcessor( 120 : argc, &argv, GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_MULTIDIM_RASTER); 121 16 : if (argc < 1) 122 1 : return (-argc); 123 : 124 30 : alg->SetCallPath(std::vector<std::string>{argv[0]}); 125 30 : std::vector<std::string> args; 126 70 : for (int i = 1; i < argc; ++i) 127 55 : args.push_back(argv[i]); 128 15 : CSLDestroy(argv); 129 : 130 15 : if (!alg->ParseCommandLineArguments(args)) 131 : { 132 3 : fprintf(stderr, "%s", alg->GetUsageForCLI(true).c_str()); 133 3 : return 1; 134 : } 135 : 136 : { 137 12 : const auto stdoutArg = alg->GetActualAlgorithm().GetArg("stdout"); 138 12 : if (stdoutArg && stdoutArg->GetType() == GAAT_BOOLEAN) 139 3 : stdoutArg->Set(true); 140 : } 141 : 142 : GDALProgressFunc pfnProgress = 143 12 : alg->IsProgressBarRequested() ? GDALTermProgress : nullptr; 144 12 : void *pProgressData = nullptr; 145 : 146 12 : int ret = 0; 147 12 : if (alg->Run(pfnProgress, pProgressData) && alg->Finalize()) 148 : { 149 : const auto outputArg = 150 11 : alg->GetActualAlgorithm().GetArg("output-string"); 151 14 : if (outputArg && outputArg->GetType() == GAAT_STRING && 152 3 : outputArg->IsOutput()) 153 : { 154 3 : printf("%s", outputArg->Get<std::string>().c_str()); 155 : } 156 : } 157 : else 158 : { 159 1 : ret = 1; 160 : } 161 : 162 12 : return ret; 163 : } 164 : 165 0 : MAIN_END