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 75 : static void EmitCompletion(std::unique_ptr<GDALAlgorithm> rootAlg, 28 : const std::vector<std::string> &argsIn, 29 : bool lastWordIsComplete) 30 : { 31 : #ifdef DEBUG_COMPLETION 32 : for (size_t i = 0; i < argsIn.size(); ++i) 33 : fprintf(stderr, "arg[%d]='%s'\n", static_cast<int>(i), 34 : argsIn[i].c_str()); 35 : #endif 36 : 37 75 : std::vector<std::string> args = argsIn; 38 : 39 75 : std::string ret; 40 33460 : const auto addSpace = [&ret]() 41 : { 42 16765 : if (!ret.empty()) 43 16695 : ret += " "; 44 16840 : }; 45 : 46 222 : if (!args.empty() && 47 74 : (args.back() == "--config" || 48 144 : STARTS_WITH(args.back().c_str(), "--config=") || 49 140 : (args.size() >= 2 && args[args.size() - 2] == "--config"))) 50 : { 51 4 : if (args.back() == "--config=" || args.back().back() != '=') 52 : { 53 4 : CPLStringList aosConfigOptions(CPLGetKnownConfigOptions()); 54 2128 : for (const char *pszOpt : cpl::Iterate(aosConfigOptions)) 55 : { 56 2126 : addSpace(); 57 2126 : ret += pszOpt; 58 2126 : ret += '='; 59 : } 60 2 : printf("%s", ret.c_str()); 61 : } 62 4 : return; 63 : } 64 : 65 14710 : for (const auto &choice : rootAlg->GetAutoComplete( 66 14710 : args, lastWordIsComplete, /*showAllOptions = */ true)) 67 : { 68 14639 : addSpace(); 69 14639 : ret += CPLString(choice).replaceAll(" ", "\\ "); 70 : } 71 : 72 : #ifdef DEBUG_COMPLETION 73 : fprintf(stderr, "ret = '%s'\n", ret.c_str()); 74 : #endif 75 71 : if (!ret.empty()) 76 68 : printf("%s", ret.c_str()); 77 : } 78 : 79 : /************************************************************************/ 80 : /* main() */ 81 : /************************************************************************/ 82 : 83 106 : MAIN_START(argc, argv) 84 : { 85 106 : auto alg = GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate( 86 318 : GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME); 87 106 : assert(alg); 88 : 89 106 : if (argc >= 3 && strcmp(argv[1], "completion") == 0) 90 : { 91 75 : GDALAllRegister(); 92 : 93 75 : const bool bLastWordIsComplete = 94 75 : EQUAL(argv[argc - 1], "last_word_is_complete=true"); 95 75 : if (STARTS_WITH(argv[argc - 1], "last_word_is_complete=")) 96 2 : --argc; 97 : 98 : // Process lines like "gdal completion gdal raster last_word_is_complete=true|false" 99 75 : EmitCompletion(std::move(alg), 100 150 : std::vector<std::string>(argv + 3, argv + argc), 101 : bLastWordIsComplete); 102 75 : return 0; 103 : } 104 : 105 31 : EarlySetConfigOptions(argc, argv); 106 : 107 : /* -------------------------------------------------------------------- */ 108 : /* Register standard GDAL drivers, and process generic GDAL */ 109 : /* command options. */ 110 : /* -------------------------------------------------------------------- */ 111 : 112 31 : GDALAllRegister(); 113 : 114 31 : argc = GDALGeneralCmdLineProcessor( 115 : argc, &argv, GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_MULTIDIM_RASTER); 116 31 : if (argc < 1) 117 1 : return (-argc); 118 : 119 60 : std::vector<std::string> args; 120 143 : for (int i = 1; i < argc; ++i) 121 113 : args.push_back(argv[i]); 122 30 : CSLDestroy(argv); 123 : 124 30 : if (!alg->ParseCommandLineArguments(args)) 125 : { 126 8 : if (strstr(CPLGetLastErrorMsg(), "Do you mean") == nullptr) 127 : { 128 5 : fprintf(stderr, "%s", alg->GetUsageForCLI(true).c_str()); 129 : } 130 8 : return 1; 131 : } 132 : 133 : { 134 22 : const auto stdoutArg = alg->GetActualAlgorithm().GetArg("stdout"); 135 22 : if (stdoutArg && stdoutArg->GetType() == GAAT_BOOLEAN) 136 4 : stdoutArg->Set(true); 137 : } 138 : 139 : GDALProgressFunc pfnProgress = 140 22 : alg->IsProgressBarRequested() ? GDALTermProgress : nullptr; 141 22 : void *pProgressData = nullptr; 142 : 143 22 : alg->SetCalledFromCommandLine(); 144 : 145 22 : int ret = 0; 146 22 : if (alg->Run(pfnProgress, pProgressData) && alg->Finalize()) 147 : { 148 : const auto outputArg = 149 21 : alg->GetActualAlgorithm().GetArg("output-string"); 150 29 : if (outputArg && outputArg->GetType() == GAAT_STRING && 151 8 : outputArg->IsOutput()) 152 : { 153 8 : printf("%s", outputArg->Get<std::string>().c_str()); 154 : } 155 : } 156 : else 157 : { 158 1 : ret = 1; 159 : } 160 : 161 22 : return ret; 162 : } 163 : 164 0 : MAIN_END