Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: GDALAlgorithm class
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 GDAL_ALGORITHM_INCLUDED
14 : #define GDAL_ALGORITHM_INCLUDED
15 :
16 : #include "cpl_port.h"
17 : #include "cpl_progress.h"
18 :
19 : #include "gdal.h"
20 :
21 : /************************************************************************/
22 : /************************************************************************/
23 : /* GDAL Algorithm C API */
24 : /************************************************************************/
25 : /************************************************************************/
26 :
27 : CPL_C_START
28 :
29 : /** Type of an argument */
30 : typedef enum GDALAlgorithmArgType
31 : {
32 : /** Boolean type. Value is a bool. */
33 : GAAT_BOOLEAN,
34 : /** Single-value string type. Value is a std::string */
35 : GAAT_STRING,
36 : /** Single-value integer type. Value is a int */
37 : GAAT_INTEGER,
38 : /** Single-value real type. Value is a double */
39 : GAAT_REAL,
40 : /** Dataset type. Value is a GDALArgDatasetValue */
41 : GAAT_DATASET,
42 : /** Multi-value string type. Value is a std::vector<std::string> */
43 : GAAT_STRING_LIST,
44 : /** Multi-value integer type. Value is a std::vector<int> */
45 : GAAT_INTEGER_LIST,
46 : /** Multi-value real type. Value is a std::vector<double> */
47 : GAAT_REAL_LIST,
48 : /** Multi-value dataset type. Value is a std::vector<GDALArgDatasetValue> */
49 : GAAT_DATASET_LIST,
50 : } GDALAlgorithmArgType;
51 :
52 : /** Return whether the argument type is a list / multi-valued one. */
53 : bool CPL_DLL GDALAlgorithmArgTypeIsList(GDALAlgorithmArgType type);
54 :
55 : /** Return the string representation of the argument type */
56 : const char CPL_DLL *GDALAlgorithmArgTypeName(GDALAlgorithmArgType type);
57 :
58 : /** Opaque C type for GDALArgDatasetValue */
59 : typedef struct GDALArgDatasetValueHS *GDALArgDatasetValueH;
60 :
61 : /** Opaque C type for GDALAlgorithmArg */
62 : typedef struct GDALAlgorithmArgHS *GDALAlgorithmArgH;
63 :
64 : /** Opaque C type for GDALAlgorithm */
65 : typedef struct GDALAlgorithmHS *GDALAlgorithmH;
66 :
67 : /** Opaque C type for GDALAlgorithmRegistry */
68 : typedef struct GDALAlgorithmRegistryHS *GDALAlgorithmRegistryH;
69 :
70 : /************************************************************************/
71 : /* GDALAlgorithmRegistryH API */
72 : /************************************************************************/
73 :
74 : GDALAlgorithmRegistryH CPL_DLL GDALGetGlobalAlgorithmRegistry(void);
75 :
76 : void CPL_DLL GDALAlgorithmRegistryRelease(GDALAlgorithmRegistryH);
77 :
78 : char CPL_DLL **GDALAlgorithmRegistryGetAlgNames(GDALAlgorithmRegistryH);
79 :
80 : GDALAlgorithmH CPL_DLL GDALAlgorithmRegistryInstantiateAlg(
81 : GDALAlgorithmRegistryH, const char *pszAlgName);
82 :
83 : /************************************************************************/
84 : /* GDALAlgorithmH API */
85 : /************************************************************************/
86 :
87 : void CPL_DLL GDALAlgorithmRelease(GDALAlgorithmH);
88 :
89 : const char CPL_DLL *GDALAlgorithmGetName(GDALAlgorithmH);
90 :
91 : const char CPL_DLL *GDALAlgorithmGetDescription(GDALAlgorithmH);
92 :
93 : const char CPL_DLL *GDALAlgorithmGetLongDescription(GDALAlgorithmH);
94 :
95 : const char CPL_DLL *GDALAlgorithmGetHelpFullURL(GDALAlgorithmH);
96 :
97 : bool CPL_DLL GDALAlgorithmHasSubAlgorithms(GDALAlgorithmH);
98 :
99 : char CPL_DLL **GDALAlgorithmGetSubAlgorithmNames(GDALAlgorithmH);
100 :
101 : GDALAlgorithmH CPL_DLL
102 : GDALAlgorithmInstantiateSubAlgorithm(GDALAlgorithmH, const char *pszSubAlgName);
103 :
104 : bool CPL_DLL GDALAlgorithmParseCommandLineArguments(GDALAlgorithmH,
105 : CSLConstList papszArgs);
106 :
107 : GDALAlgorithmH CPL_DLL GDALAlgorithmGetActualAlgorithm(GDALAlgorithmH);
108 :
109 : bool CPL_DLL GDALAlgorithmRun(GDALAlgorithmH, GDALProgressFunc pfnProgress,
110 : void *pProgressData);
111 :
112 : bool CPL_DLL GDALAlgorithmFinalize(GDALAlgorithmH);
113 :
114 : char CPL_DLL *GDALAlgorithmGetUsageAsJSON(GDALAlgorithmH);
115 :
116 : char CPL_DLL **GDALAlgorithmGetArgNames(GDALAlgorithmH);
117 :
118 : GDALAlgorithmArgH CPL_DLL GDALAlgorithmGetArg(GDALAlgorithmH,
119 : const char *pszArgName);
120 :
121 : /************************************************************************/
122 : /* GDALAlgorithmArgH API */
123 : /************************************************************************/
124 :
125 : void CPL_DLL GDALAlgorithmArgRelease(GDALAlgorithmArgH);
126 :
127 : const char CPL_DLL *GDALAlgorithmArgGetName(GDALAlgorithmArgH);
128 :
129 : GDALAlgorithmArgType CPL_DLL GDALAlgorithmArgGetType(GDALAlgorithmArgH);
130 :
131 : const char CPL_DLL *GDALAlgorithmArgGetDescription(GDALAlgorithmArgH);
132 :
133 : const char CPL_DLL *GDALAlgorithmArgGetShortName(GDALAlgorithmArgH);
134 :
135 : char CPL_DLL **GDALAlgorithmArgGetAliases(GDALAlgorithmArgH);
136 :
137 : const char CPL_DLL *GDALAlgorithmArgGetMetaVar(GDALAlgorithmArgH);
138 :
139 : const char CPL_DLL *GDALAlgorithmArgGetCategory(GDALAlgorithmArgH);
140 :
141 : bool CPL_DLL GDALAlgorithmArgIsPositional(GDALAlgorithmArgH);
142 :
143 : bool CPL_DLL GDALAlgorithmArgIsRequired(GDALAlgorithmArgH);
144 :
145 : int CPL_DLL GDALAlgorithmArgGetMinCount(GDALAlgorithmArgH);
146 :
147 : int CPL_DLL GDALAlgorithmArgGetMaxCount(GDALAlgorithmArgH);
148 :
149 : bool CPL_DLL GDALAlgorithmArgGetPackedValuesAllowed(GDALAlgorithmArgH);
150 :
151 : bool CPL_DLL GDALAlgorithmArgGetRepeatedArgAllowed(GDALAlgorithmArgH);
152 :
153 : char CPL_DLL **GDALAlgorithmArgGetChoices(GDALAlgorithmArgH);
154 :
155 : bool CPL_DLL GDALAlgorithmArgIsExplicitlySet(GDALAlgorithmArgH);
156 :
157 : bool CPL_DLL GDALAlgorithmArgHasDefaultValue(GDALAlgorithmArgH);
158 :
159 : bool CPL_DLL GDALAlgorithmArgIsHiddenForCLI(GDALAlgorithmArgH);
160 :
161 : bool CPL_DLL GDALAlgorithmArgIsOnlyForCLI(GDALAlgorithmArgH);
162 :
163 : bool CPL_DLL GDALAlgorithmArgIsInput(GDALAlgorithmArgH);
164 :
165 : bool CPL_DLL GDALAlgorithmArgIsOutput(GDALAlgorithmArgH);
166 :
167 : const char CPL_DLL *GDALAlgorithmArgGetMutualExclusionGroup(GDALAlgorithmArgH);
168 :
169 : bool CPL_DLL GDALAlgorithmArgGetAsBoolean(GDALAlgorithmArgH);
170 :
171 : const char CPL_DLL *GDALAlgorithmArgGetAsString(GDALAlgorithmArgH);
172 :
173 : GDALArgDatasetValueH
174 : CPL_DLL GDALAlgorithmArgGetAsDatasetValue(GDALAlgorithmArgH);
175 :
176 : int CPL_DLL GDALAlgorithmArgGetAsInteger(GDALAlgorithmArgH);
177 :
178 : double CPL_DLL GDALAlgorithmArgGetAsDouble(GDALAlgorithmArgH);
179 :
180 : char CPL_DLL **GDALAlgorithmArgGetAsStringList(GDALAlgorithmArgH);
181 :
182 : const int CPL_DLL *GDALAlgorithmArgGetAsIntegerList(GDALAlgorithmArgH,
183 : size_t *pnCount);
184 :
185 : const double CPL_DLL *GDALAlgorithmArgGetAsDoubleList(GDALAlgorithmArgH,
186 : size_t *pnCount);
187 :
188 : bool CPL_DLL GDALAlgorithmArgSetAsBoolean(GDALAlgorithmArgH, bool);
189 :
190 : bool CPL_DLL GDALAlgorithmArgSetAsString(GDALAlgorithmArgH, const char *);
191 :
192 : bool CPL_DLL GDALAlgorithmArgSetAsDatasetValue(GDALAlgorithmArgH hArg,
193 : GDALArgDatasetValueH value);
194 :
195 : bool CPL_DLL GDALAlgorithmArgSetDataset(GDALAlgorithmArgH hArg, GDALDatasetH);
196 :
197 : bool CPL_DLL GDALAlgorithmArgSetDatasets(GDALAlgorithmArgH hArg, size_t nCount,
198 : GDALDatasetH *);
199 :
200 : bool CPL_DLL GDALAlgorithmArgSetDatasetNames(GDALAlgorithmArgH hArg,
201 : CSLConstList);
202 :
203 : bool CPL_DLL GDALAlgorithmArgSetAsInteger(GDALAlgorithmArgH, int);
204 :
205 : bool CPL_DLL GDALAlgorithmArgSetAsDouble(GDALAlgorithmArgH, double);
206 :
207 : bool CPL_DLL GDALAlgorithmArgSetAsStringList(GDALAlgorithmArgH, CSLConstList);
208 :
209 : bool CPL_DLL GDALAlgorithmArgSetAsIntegerList(GDALAlgorithmArgH, size_t nCount,
210 : const int *pnValues);
211 :
212 : bool CPL_DLL GDALAlgorithmArgSetAsDoubleList(GDALAlgorithmArgH, size_t nCount,
213 : const double *pnValues);
214 :
215 : /************************************************************************/
216 : /* GDALArgDatasetValueH API */
217 : /************************************************************************/
218 :
219 : GDALArgDatasetValueH CPL_DLL GDALArgDatasetValueCreate(void);
220 :
221 : void CPL_DLL GDALArgDatasetValueRelease(GDALArgDatasetValueH);
222 :
223 : const char CPL_DLL *GDALArgDatasetValueGetName(GDALArgDatasetValueH);
224 :
225 : GDALDatasetH CPL_DLL GDALArgDatasetValueGetDatasetRef(GDALArgDatasetValueH);
226 :
227 : GDALDatasetH
228 : CPL_DLL GDALArgDatasetValueGetDatasetIncreaseRefCount(GDALArgDatasetValueH);
229 :
230 : /** Bit indicating that the name component of GDALArgDatasetValue is accepted. */
231 : #define GADV_NAME (1 << 0)
232 : /** Bit indicating that the dataset component of GDALArgDatasetValue is accepted. */
233 : #define GADV_OBJECT (1 << 1)
234 :
235 : /** Binary-or combination of GDAL_OF_RASTER, GDAL_OF_VECTOR and
236 : * GDAL_OF_MULTIDIM_RASTER.
237 : */
238 : typedef int GDALArgDatasetValueType;
239 :
240 : GDALArgDatasetValueType
241 : CPL_DLL GDALArgDatasetValueGetType(GDALArgDatasetValueH);
242 :
243 : int CPL_DLL GDALArgDatasetValueGetInputFlags(GDALArgDatasetValueH);
244 :
245 : int CPL_DLL GDALArgDatasetValueGetOutputFlags(GDALArgDatasetValueH);
246 :
247 : void CPL_DLL GDALArgDatasetValueSetName(GDALArgDatasetValueH, const char *);
248 :
249 : void CPL_DLL GDALArgDatasetValueSetDataset(GDALArgDatasetValueH, GDALDatasetH);
250 :
251 : CPL_C_END
252 :
253 : /************************************************************************/
254 : /************************************************************************/
255 : /* GDAL Algorithm C++ API */
256 : /************************************************************************/
257 : /************************************************************************/
258 :
259 : // The rest of this header requires C++17
260 : // _MSC_VER >= 1920 : Visual Studio >= 2019
261 : #if defined(__cplusplus) && !defined(CPL_SUPRESS_CPLUSPLUS) && \
262 : (defined(DOXYGEN_SKIP) || __cplusplus >= 201703L || _MSC_VER >= 1920)
263 :
264 : #include "cpl_error.h"
265 :
266 : #include <limits>
267 : #include <functional>
268 : #include <map>
269 : #include <memory>
270 : #include <string>
271 : #include <type_traits>
272 : #include <utility>
273 : #include <variant>
274 : #include <vector>
275 :
276 : class GDALDataset;
277 :
278 : /** Common argument category */
279 : constexpr const char *GAAC_COMMON = "Common";
280 :
281 : /** Base argument category */
282 : constexpr const char *GAAC_BASE = "Base";
283 :
284 : /** Advanced argument category */
285 : constexpr const char *GAAC_ADVANCED = "Advanced";
286 :
287 : /** Esoteric argument category */
288 : constexpr const char *GAAC_ESOTERIC = "Esoteric";
289 :
290 : /** Argument metadata item that applies to the "input-format" and
291 : * "output-format" argument */
292 : constexpr const char *GAAMDI_REQUIRED_CAPABILITIES = "required_capabilities";
293 :
294 : /** Name of the argument for an input dataset. */
295 : constexpr const char *GDAL_ARG_NAME_INPUT = "input";
296 :
297 : /** Name of the argument for an output dataset. */
298 : constexpr const char *GDAL_ARG_NAME_OUTPUT = "output";
299 :
300 : /** Name of the argument for update. */
301 : constexpr const char *GDAL_ARG_NAME_UPDATE = "update";
302 :
303 : /** Name of the argument for read-only. */
304 : constexpr const char *GDAL_ARG_NAME_READ_ONLY = "read-only";
305 :
306 : /************************************************************************/
307 : /* GDALArgDatasetValue */
308 : /************************************************************************/
309 :
310 : /** Return the string representation of GDALArgDatasetValueType */
311 : std::string CPL_DLL GDALArgDatasetValueTypeName(GDALArgDatasetValueType);
312 :
313 : class GDALAlgorithmArg;
314 :
315 : /** Value for an argument that points to a GDALDataset.
316 : *
317 : * This is the value of arguments of type GAAT_DATASET or GAAT_DATASET_LIST.
318 : */
319 : class CPL_DLL GDALArgDatasetValue final
320 : {
321 : public:
322 : /** Default (empty) constructor */
323 1201 : GDALArgDatasetValue() = default;
324 :
325 : /** Constructor by dataset name. */
326 22 : explicit GDALArgDatasetValue(const std::string &name) : m_name(name)
327 : {
328 22 : }
329 :
330 : /** Constructor by dataset instance, increasing its reference counter */
331 : explicit GDALArgDatasetValue(GDALDataset *poDS);
332 :
333 : /** Move constructor */
334 : GDALArgDatasetValue(GDALArgDatasetValue &&other);
335 :
336 : /** Destructor. Decrease m_poDS reference count, and destroy it if no
337 : * longer referenced. */
338 : ~GDALArgDatasetValue();
339 :
340 : /** Dereference the dataset object and close it if no longer referenced.
341 : * Return an error if an error occurred during dataset closing. */
342 : bool Close();
343 :
344 : /** Move-assignment operator */
345 : GDALArgDatasetValue &operator=(GDALArgDatasetValue &&other);
346 :
347 : /** Get the GDALDataset* instance (may be null), and increase its reference
348 : * count if not null. Once done with the dataset, the caller should call
349 : * GDALDataset::Release().
350 : */
351 : GDALDataset *GetDatasetIncreaseRefCount();
352 :
353 : /** Get a GDALDataset* instance (may be null). This does not modify the
354 : * reference counter, hence the lifetime of the returned object is not
355 : * guaranteed to exceed the one of this instance.
356 : */
357 2066 : GDALDataset *GetDatasetRef()
358 : {
359 2066 : return m_poDS;
360 : }
361 :
362 : /** Borrow the GDALDataset* instance (may be null), leaving its reference
363 : * counter unchanged.
364 : */
365 1 : GDALDataset *BorrowDataset()
366 : {
367 1 : GDALDataset *ret = m_poDS;
368 1 : m_poDS = nullptr;
369 1 : return ret;
370 : }
371 :
372 : /** Borrow the GDALDataset* instance from another GDALArgDatasetValue,
373 : * leaving its reference counter unchange.
374 : */
375 : void BorrowDatasetFrom(GDALArgDatasetValue &other)
376 : {
377 : Close();
378 : m_poDS = other.BorrowDataset();
379 : m_name = other.m_name;
380 : }
381 :
382 : /** Get dataset name */
383 410 : const std::string &GetName() const
384 : {
385 410 : return m_name;
386 : }
387 :
388 : /** Return whether a dataset name has been set */
389 324 : bool IsNameSet() const
390 : {
391 324 : return m_nameSet;
392 : }
393 :
394 : /** Indicates which components among name and dataset are accepted as
395 : * input, when this argument serves as an input.
396 : *
397 : * If the GADV_NAME bit is set, it indicates a dataset name is accepted as
398 : * input.
399 : * If the GADV_OBJECT bit is set, it indicates a dataset object is
400 : * accepted as input.
401 : * If both bits are set, the algorithm can accept either a name or a dataset
402 : * object.
403 : */
404 103 : int GetInputFlags() const
405 : {
406 103 : return m_inputFlags;
407 : }
408 :
409 : /** Indicates which components among name and dataset are modified,
410 : * when this argument serves as an output.
411 : *
412 : * If the GADV_NAME bit is set, it indicates a dataset name is generated as
413 : * output (that is the algorithm will generate the name. Rarely used).
414 : * If the GADV_OBJECT bit is set, it indicates a dataset object is
415 : * generated as output, and available for use after the algorithm has
416 : * completed.
417 : */
418 30 : int GetOutputFlags() const
419 : {
420 30 : return m_outputFlags;
421 : }
422 :
423 : /** Set dataset name */
424 : void Set(const std::string &name);
425 :
426 : /** Transfer dataset to this instance (does not affect is reference
427 : * counter). */
428 : void Set(std::unique_ptr<GDALDataset> poDS);
429 :
430 : /** Set dataset object, increasing its reference counter. */
431 : void Set(GDALDataset *poDS);
432 :
433 : /** Set from other value, increasing the reference counter of the
434 : * GDALDataset object.
435 : */
436 : void SetFrom(const GDALArgDatasetValue &other);
437 :
438 : /** Set which components among name and dataset are accepted as
439 : * input, when this argument serves as an input.
440 : * Should only be used by GDALAlgorithm sub-classes.
441 : */
442 573 : void SetInputFlags(int flags)
443 : {
444 573 : m_inputFlags = flags;
445 573 : }
446 :
447 : /** Set which components among name and dataset are modified when this
448 : * argument serves as an output.
449 : * Should only be used by GDALAlgorithm sub-classes.
450 : */
451 323 : void SetOutputFlags(int flags)
452 : {
453 323 : m_outputFlags = flags;
454 323 : }
455 :
456 : /** Get which type of dataset is allowed / generated.
457 : * Binary-or combination of GDAL_OF_RASTER, GDAL_OF_VECTOR and
458 : * GDAL_OF_MULTIDIM_RASTER, possibly combined with GDAL_OF_UPDATE.
459 : */
460 357 : GDALArgDatasetValueType GetType() const
461 : {
462 357 : return m_type;
463 : }
464 :
465 : /** Set which type of dataset is allowed / generated.
466 : * Binary-or combination of GDAL_OF_RASTER, GDAL_OF_VECTOR and
467 : * GDAL_OF_MULTIDIM_RASTER.
468 : */
469 781 : void SetType(GDALArgDatasetValueType type)
470 : {
471 781 : m_type = type;
472 781 : }
473 :
474 : protected:
475 : friend class GDALAlgorithm;
476 :
477 : /** Set the argument that owns us. */
478 781 : void SetOwnerArgument(GDALAlgorithmArg *arg)
479 : {
480 781 : CPLAssert(!m_ownerArg);
481 781 : m_ownerArg = arg;
482 781 : }
483 :
484 : private:
485 : /** The owner argument (may be nullptr for freestanding objects) */
486 : GDALAlgorithmArg *m_ownerArg = nullptr;
487 :
488 : /** Dataset object. */
489 : GDALDataset *m_poDS = nullptr;
490 :
491 : /** Dataset name */
492 : std::string m_name{};
493 :
494 : /** Whether a dataset name (possibly empty for a MEM dataset...) has been set */
495 : bool m_nameSet = false;
496 :
497 : /** Dataset type */
498 : GDALArgDatasetValueType m_type =
499 : GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_MULTIDIM_RASTER;
500 :
501 : /** Which components among name and dataset are accepted as
502 : * input, when this argument serves as an input.
503 : */
504 : int m_inputFlags = GADV_NAME | GADV_OBJECT;
505 :
506 : /** Which components among name and dataset are generated as
507 : * output, when this argument serves as an output.
508 : */
509 : int m_outputFlags = GADV_OBJECT;
510 :
511 : GDALArgDatasetValue(const GDALArgDatasetValue &) = delete;
512 : GDALArgDatasetValue &operator=(const GDALArgDatasetValue &) = delete;
513 : };
514 :
515 : /************************************************************************/
516 : /* GDALAlgorithmArgDecl */
517 : /************************************************************************/
518 :
519 : /** Argument declaration.
520 : *
521 : * It does not hold its value.
522 : */
523 : class CPL_DLL GDALAlgorithmArgDecl final
524 : {
525 : public:
526 : /** Special value for the SetMaxCount() / GetMaxCount() to indicate
527 : * unlimited number of values. */
528 : static constexpr int UNBOUNDED = std::numeric_limits<int>::max();
529 :
530 : /** Constructor.
531 : *
532 : * @param longName Long name. Must be 2 characters at least. Must not start
533 : * with dash.
534 : * @param chShortName 1-letter short name, or NUL character
535 : * @param description Description.
536 : * @param type Type of the argument.
537 : */
538 : GDALAlgorithmArgDecl(const std::string &longName, char chShortName,
539 : const std::string &description,
540 : GDALAlgorithmArgType type);
541 :
542 : /** Declare an alias. Must be 2 characters at least. */
543 2195 : GDALAlgorithmArgDecl &AddAlias(const std::string &alias)
544 : {
545 2195 : m_aliases.push_back(alias);
546 2195 : return *this;
547 : }
548 :
549 : /** Declare an hidden alias (i.e. not exposed in usage).
550 : * Must be 2 characters at least. */
551 352 : GDALAlgorithmArgDecl &AddHiddenAlias(const std::string &alias)
552 : {
553 352 : m_hiddenAliases.push_back(alias);
554 352 : return *this;
555 : }
556 :
557 : /** Declare that the argument is positional. Typically input / output files
558 : */
559 733 : GDALAlgorithmArgDecl &SetPositional()
560 : {
561 733 : m_positional = true;
562 733 : return *this;
563 : }
564 :
565 : /** Declare that the argument is required. Default is no
566 : */
567 562 : GDALAlgorithmArgDecl &SetRequired()
568 : {
569 562 : m_required = true;
570 562 : return *this;
571 : }
572 :
573 : /** Declare the "meta-var" hint.
574 : * By default, the meta-var value is the long name of the argument in
575 : * upper case.
576 : */
577 2143 : GDALAlgorithmArgDecl &SetMetaVar(const std::string &metaVar)
578 : {
579 2143 : m_metaVar = metaVar;
580 2143 : return *this;
581 : }
582 :
583 : /** Declare the argument category: GAAC_COMMON, GAAC_BASE, GAAC_ADVANCED,
584 : * GAAC_ESOTERIC or a custom category.
585 : */
586 6966 : GDALAlgorithmArgDecl &SetCategory(const std::string &category)
587 : {
588 6966 : m_category = category;
589 6966 : return *this;
590 : }
591 :
592 : /** Declare a default value for the argument.
593 : */
594 855 : template <class T> GDALAlgorithmArgDecl &SetDefault(const T &value)
595 : {
596 855 : m_hasDefaultValue = true;
597 : if constexpr (std::is_same_v<T, int>)
598 : {
599 2 : if (m_type == GAAT_REAL)
600 : {
601 1 : m_defaultValue = static_cast<double>(value);
602 1 : return *this;
603 : }
604 : }
605 854 : m_defaultValue = value;
606 854 : return *this;
607 : }
608 :
609 : /** Declare the minimum number of values for the argument. Defaults to 0.
610 : * Only applies to list type of arguments.
611 : * Setting it to non-zero does *not* make the argument required. It just
612 : * sets the minimum number of values when it is specified. To also make
613 : * it required, use SetRequired().
614 : */
615 : GDALAlgorithmArgDecl &SetMinCount(int count);
616 :
617 : /** Declare the maximum number of values for the argument.
618 : * Defaults to 1 for scalar types, and UNBOUNDED for list types.
619 : * Only applies to list type of arguments.
620 : */
621 : GDALAlgorithmArgDecl &SetMaxCount(int count);
622 :
623 : /** Declare whether in --help message one should display hints about the
624 : * minimum/maximum number of values. Defaults to true.
625 : */
626 132 : GDALAlgorithmArgDecl &SetDisplayHintAboutRepetition(bool displayHint)
627 : {
628 132 : m_displayHintAboutRepetition = displayHint;
629 132 : return *this;
630 : }
631 :
632 : /** Declares whether, for list type of arguments, several values, space
633 : * separated, may be specified. That is "--foo=bar,baz".
634 : * The default is true.
635 : */
636 3 : GDALAlgorithmArgDecl &SetPackedValuesAllowed(bool allowed)
637 : {
638 3 : m_packedValuesAllowed = allowed;
639 3 : return *this;
640 : }
641 :
642 : /** Declares whether, for list type of arguments, the argument may be
643 : * repeated. That is "--foo=bar --foo=baz".
644 : * The default is true.
645 : */
646 180 : GDALAlgorithmArgDecl &SetRepeatedArgAllowed(bool allowed)
647 : {
648 180 : m_repeatedArgAllowed = allowed;
649 180 : return *this;
650 : }
651 :
652 : //! @cond Doxygen_Suppress
653 154 : GDALAlgorithmArgDecl &SetChoices()
654 : {
655 154 : return *this;
656 : }
657 :
658 : //! @endcond
659 :
660 : /** Declares the allowed values (as strings) for the argument.
661 : * Only honored for GAAT_STRING and GAAT_STRING_LIST types.
662 : */
663 : template <typename T, typename... U>
664 706 : GDALAlgorithmArgDecl &SetChoices(T &&first, U &&...rest)
665 : {
666 706 : m_choices.push_back(std::forward<T>(first));
667 706 : SetChoices(std::forward<U>(rest)...);
668 706 : return *this;
669 : }
670 :
671 : //! @cond Doxygen_Suppress
672 40 : GDALAlgorithmArgDecl &SetHiddenChoices()
673 : {
674 40 : return *this;
675 : }
676 :
677 : //! @endcond
678 :
679 : /** Declares the, hidden, allowed values (as strings) for the argument.
680 : * Only honored for GAAT_STRING and GAAT_STRING_LIST types.
681 : */
682 : template <typename T, typename... U>
683 40 : GDALAlgorithmArgDecl &SetHiddenChoices(T &&first, U &&...rest)
684 : {
685 40 : m_hiddenChoices.push_back(std::forward<T>(first));
686 40 : SetHiddenChoices(std::forward<U>(rest)...);
687 40 : return *this;
688 : }
689 :
690 : /** Declare that the argument must not be mentioned in CLI usage.
691 : * For example, "output-value" for "gdal raster info", which is only
692 : * meant when the algorithm is used from a non-CLI context.
693 : */
694 2523 : GDALAlgorithmArgDecl &SetHiddenForCLI(bool hiddenForCLI = true)
695 : {
696 2523 : m_hiddenForCLI = hiddenForCLI;
697 2523 : return *this;
698 : }
699 :
700 : /** Declare that the argument is only for CLI usage.
701 : * For example "--help" */
702 5752 : GDALAlgorithmArgDecl &SetOnlyForCLI(bool onlyForCLI = true)
703 : {
704 5752 : m_onlyForCLI = onlyForCLI;
705 5752 : return *this;
706 : }
707 :
708 : /** Indicate whether the value of the argument is read-only during the
709 : * execution of the algorithm. Default is true.
710 : */
711 401 : GDALAlgorithmArgDecl &SetIsInput(bool isInput = true)
712 : {
713 401 : m_isInput = isInput;
714 401 : return *this;
715 : }
716 :
717 : /** Indicate whether (at least part of) the value of the argument is set
718 : * during the execution of the algorithm.
719 : * For example, "output-value" for "gdal raster info"
720 : * Default is false.
721 : * An argument may return both IsInput() and IsOutput() as true.
722 : * For example the "gdal raster convert" algorithm consumes the dataset
723 : * name of its "output" argument, and sets the dataset object during its
724 : * execution.
725 : */
726 401 : GDALAlgorithmArgDecl &SetIsOutput(bool isOutput = true)
727 : {
728 401 : m_isOutput = isOutput;
729 401 : return *this;
730 : }
731 :
732 : /** Set the name of the mutual exclusion group to which this argument
733 : * belongs to. At most one argument in a group can be specified.
734 : */
735 278 : GDALAlgorithmArgDecl &SetMutualExclusionGroup(const std::string &group)
736 : {
737 278 : m_mutualExclusionGroup = group;
738 278 : return *this;
739 : }
740 :
741 : /** Set user-defined metadata item.
742 : */
743 : GDALAlgorithmArgDecl &
744 662 : AddMetadataItem(const std::string &name,
745 : const std::vector<std::string> &values)
746 : {
747 662 : m_metadata[name] = values;
748 662 : return *this;
749 : }
750 :
751 : /** Set that this (string) argument accepts the \@filename syntax to
752 : * mean that the content of the specified file should be used as the
753 : * value of the argument.
754 : */
755 73 : GDALAlgorithmArgDecl &SetReadFromFileAtSyntaxAllowed()
756 : {
757 73 : m_readFromFileAtSyntaxAllowed = true;
758 73 : return *this;
759 : }
760 :
761 : /** Sets that SQL comments must be removed from a (string) argument.
762 : */
763 72 : GDALAlgorithmArgDecl &SetRemoveSQLCommentsEnabled()
764 : {
765 72 : m_removeSQLComments = true;
766 72 : return *this;
767 : }
768 :
769 : /** Sets whether the dataset should be opened automatically by
770 : * GDALAlgorithm. Only applies to GAAT_DATASET and GAAT_DATASET_LIST.
771 : */
772 24 : GDALAlgorithmArgDecl &SetAutoOpenDataset(bool autoOpen)
773 : {
774 24 : m_autoOpenDataset = autoOpen;
775 24 : return *this;
776 : }
777 :
778 : /** Return the (long) name */
779 13774 : inline const std::string &GetName() const
780 : {
781 13774 : return m_longName;
782 : }
783 :
784 : /** Return the short name, or empty string if there is none */
785 11663 : inline const std::string &GetShortName() const
786 : {
787 11663 : return m_shortName;
788 : }
789 :
790 : /** Return the aliases (potentially none) */
791 500 : inline const std::vector<std::string> &GetAliases() const
792 : {
793 500 : return m_aliases;
794 : }
795 :
796 : /** Return the description */
797 759 : inline const std::string &GetDescription() const
798 : {
799 759 : return m_description;
800 : }
801 :
802 : /** Return the "meta-var" hint.
803 : * By default, the meta-var value is the long name of the argument in
804 : * upper case.
805 : */
806 509 : inline const std::string &GetMetaVar() const
807 : {
808 509 : return m_metaVar;
809 : }
810 :
811 : /** Return the argument category: GAAC_COMMON, GAAC_BASE, GAAC_ADVANCED,
812 : * GAAC_ESOTERIC or a custom category.
813 : */
814 1322 : inline const std::string &GetCategory() const
815 : {
816 1322 : return m_category;
817 : }
818 :
819 : /** Return the type */
820 14986 : inline GDALAlgorithmArgType GetType() const
821 : {
822 14986 : return m_type;
823 : }
824 :
825 : /** Return the allowed values (as strings) for the argument.
826 : * Only honored for GAAT_STRING and GAAT_STRING_LIST types.
827 : */
828 1007 : inline const std::vector<std::string> &GetChoices() const
829 : {
830 1007 : return m_choices;
831 : }
832 :
833 : /** Return the allowed hidden values (as strings) for the argument.
834 : * Only honored for GAAT_STRING and GAAT_STRING_LIST types.
835 : */
836 174 : inline const std::vector<std::string> &GetHiddenChoices() const
837 : {
838 174 : return m_hiddenChoices;
839 : }
840 :
841 : /** Return whether the argument is required. Defaults to false.
842 : */
843 8332 : inline bool IsRequired() const
844 : {
845 8332 : return m_required;
846 : }
847 :
848 : /** Return the minimum number of values for the argument. Defaults to 0.
849 : * Only applies to list type of arguments.
850 : */
851 1468 : inline int GetMinCount() const
852 : {
853 1468 : return m_minCount;
854 : }
855 :
856 : /** Return the maximum number of values for the argument.
857 : * Defaults to 1 for scalar types, and UNBOUNDED for list types.
858 : * Only applies to list type of arguments.
859 : */
860 1188 : inline int GetMaxCount() const
861 : {
862 1188 : return m_maxCount;
863 : }
864 :
865 : /** Returns whether in --help message one should display hints about the
866 : * minimum/maximum number of values. Defaults to true.
867 : */
868 324 : inline bool GetDisplayHintAboutRepetition() const
869 : {
870 324 : return m_displayHintAboutRepetition;
871 : }
872 :
873 : /** Return whether, for list type of arguments, several values, space
874 : * separated, may be specified. That is "--foo=bar,baz".
875 : * The default is true.
876 : */
877 264 : inline bool GetPackedValuesAllowed() const
878 : {
879 264 : return m_packedValuesAllowed;
880 : }
881 :
882 : /** Return whether, for list type of arguments, the argument may be
883 : * repeated. That is "--foo=bar --foo=baz".
884 : * The default is true.
885 : */
886 693 : inline bool GetRepeatedArgAllowed() const
887 : {
888 693 : return m_repeatedArgAllowed;
889 : }
890 :
891 : /** Return if the argument is a positional one. */
892 1524 : inline bool IsPositional() const
893 : {
894 1524 : return m_positional;
895 : }
896 :
897 : /** Return if the argument has a declared default value. */
898 11777 : inline bool HasDefaultValue() const
899 : {
900 11777 : return m_hasDefaultValue;
901 : }
902 :
903 : /** Return whether the argument must not be mentioned in CLI usage.
904 : * For example, "output-value" for "gdal raster info", which is only
905 : * meant when the algorithm is used from a non-CLI context.
906 : */
907 1116 : inline bool IsHiddenForCLI() const
908 : {
909 1116 : return m_hiddenForCLI;
910 : }
911 :
912 : /** Return whether the argument is only for CLI usage.
913 : * For example "--help" */
914 2449 : inline bool IsOnlyForCLI() const
915 : {
916 2449 : return m_onlyForCLI;
917 : }
918 :
919 : /** Indicate whether the value of the argument is read-only during the
920 : * execution of the algorithm. Default is true.
921 : */
922 1367 : inline bool IsInput() const
923 : {
924 1367 : return m_isInput;
925 : }
926 :
927 : /** Return whether (at least part of) the value of the argument is set
928 : * during the execution of the algorithm.
929 : * For example, "output-value" for "gdal raster info"
930 : * Default is false.
931 : * An argument may return both IsInput() and IsOutput() as true.
932 : * For example the "gdal raster convert" algorithm consumes the dataset
933 : * name of its "output" argument, and sets the dataset object during its
934 : * execution.
935 : */
936 1940 : inline bool IsOutput() const
937 : {
938 1940 : return m_isOutput;
939 : }
940 :
941 : /** Return the name of the mutual exclusion group to which this argument
942 : * belongs to, or empty string if it does not belong to any exclusion
943 : * group.
944 : */
945 1730 : inline const std::string &GetMutualExclusionGroup() const
946 : {
947 1730 : return m_mutualExclusionGroup;
948 : }
949 :
950 : /** Return if this (string) argument accepts the \@filename syntax to
951 : * mean that the content of the specified file should be used as the
952 : * value of the argument.
953 : */
954 135 : inline bool IsReadFromFileAtSyntaxAllowed() const
955 : {
956 135 : return m_readFromFileAtSyntaxAllowed;
957 : }
958 :
959 : /** Returns whether SQL comments must be removed from a (string) argument.
960 : */
961 134 : bool IsRemoveSQLCommentsEnabled() const
962 : {
963 134 : return m_removeSQLComments;
964 : }
965 :
966 : /** Returns whether the dataset should be opened automatically by
967 : * GDALAlgorithm. Only applies to GAAT_DATASET and GAAT_DATASET_LIST.
968 : */
969 352 : bool AutoOpenDataset() const
970 : {
971 352 : return m_autoOpenDataset;
972 : }
973 :
974 : /** Get user-defined metadata. */
975 : inline const std::map<std::string, std::vector<std::string>>
976 433 : GetMetadata() const
977 : {
978 433 : return m_metadata;
979 : }
980 :
981 : /** Get user-defined metadata by item name. */
982 : inline const std::vector<std::string> *
983 257 : GetMetadataItem(const std::string &name) const
984 : {
985 257 : const auto iter = m_metadata.find(name);
986 257 : return iter == m_metadata.end() ? nullptr : &(iter->second);
987 : }
988 :
989 : /** Return the default value of the argument.
990 : * Must be called with T consistent of the type of the algorithm, and only
991 : * if HasDefaultValue() is true.
992 : * Valid T types are:
993 : * - bool for GAAT_BOOLEAN
994 : * - int for GAAT_INTEGER
995 : * - double for GAAT_REAL
996 : * - std::string for GAAT_STRING
997 : * - GDALArgDatasetValue for GAAT_DATASET
998 : * - std::vector<int> for GAAT_INTEGER_LIST
999 : * - std::vector<double for GAAT_REAL_LIST
1000 : * - std::vector<std::string> for GAAT_STRING_LIST
1001 : * - std::vector<GDALArgDatasetValue> for GAAT_DATASET_LIST
1002 : */
1003 75 : template <class T> inline const T &GetDefault() const
1004 : {
1005 75 : return std::get<T>(m_defaultValue);
1006 : }
1007 :
1008 : private:
1009 : const std::string m_longName;
1010 : const std::string m_shortName;
1011 : const std::string m_description;
1012 : const GDALAlgorithmArgType m_type;
1013 : std::string m_category = GAAC_BASE;
1014 : std::string m_metaVar{};
1015 : std::string m_mutualExclusionGroup{};
1016 : int m_minCount = 0;
1017 : int m_maxCount = 0;
1018 : bool m_required = false;
1019 : bool m_positional = false;
1020 : bool m_hasDefaultValue = false;
1021 : bool m_hiddenForCLI = false;
1022 : bool m_onlyForCLI = false;
1023 : bool m_isInput = true;
1024 : bool m_isOutput = false;
1025 : bool m_packedValuesAllowed = true;
1026 : bool m_repeatedArgAllowed = true;
1027 : bool m_displayHintAboutRepetition = true;
1028 : bool m_readFromFileAtSyntaxAllowed = false;
1029 : bool m_removeSQLComments = false;
1030 : bool m_autoOpenDataset = true;
1031 : std::map<std::string, std::vector<std::string>> m_metadata{};
1032 : std::vector<std::string> m_aliases{};
1033 : std::vector<std::string> m_hiddenAliases{};
1034 : std::vector<std::string> m_choices{};
1035 : std::vector<std::string> m_hiddenChoices{};
1036 : std::variant<bool, std::string, int, double, std::vector<std::string>,
1037 : std::vector<int>, std::vector<double>>
1038 : m_defaultValue{};
1039 : };
1040 :
1041 : /************************************************************************/
1042 : /* GDALAlgorithmArg */
1043 : /************************************************************************/
1044 :
1045 : class GDALAlgorithm;
1046 :
1047 : /** Argument of an algorithm.
1048 : */
1049 : class CPL_DLL GDALAlgorithmArg /* non-final */
1050 : {
1051 : public:
1052 : /** Constructor */
1053 : template <class T>
1054 11060 : GDALAlgorithmArg(const GDALAlgorithmArgDecl &decl, T *pValue)
1055 11060 : : m_decl(decl), m_value(pValue)
1056 : {
1057 : if constexpr (!std::is_same_v<T, GDALArgDatasetValue> &&
1058 : !std::is_same_v<T, std::vector<GDALArgDatasetValue>>)
1059 : {
1060 10246 : if (decl.HasDefaultValue())
1061 2 : *std::get<T *>(m_value) = decl.GetDefault<T>();
1062 : }
1063 11060 : }
1064 :
1065 : /** Return the argument declaration. */
1066 : const GDALAlgorithmArgDecl &GetDeclaration() const
1067 : {
1068 : return m_decl;
1069 : }
1070 :
1071 : /** Alias for GDALAlgorithmArgDecl::GetName() */
1072 13772 : inline const std::string &GetName() const
1073 : {
1074 13772 : return m_decl.GetName();
1075 : }
1076 :
1077 : /** Alias for GDALAlgorithmArgDecl::GetShortName() */
1078 11663 : inline const std::string &GetShortName() const
1079 : {
1080 11663 : return m_decl.GetShortName();
1081 : }
1082 :
1083 : /** Alias for GDALAlgorithmArgDecl::GetAliases() */
1084 500 : inline const std::vector<std::string> &GetAliases() const
1085 : {
1086 500 : return m_decl.GetAliases();
1087 : }
1088 :
1089 : /** Alias for GDALAlgorithmArgDecl::GetDescription() */
1090 759 : inline const std::string &GetDescription() const
1091 : {
1092 759 : return m_decl.GetDescription();
1093 : }
1094 :
1095 : /** Alias for GDALAlgorithmArgDecl::GetMetaVar() */
1096 509 : inline const std::string &GetMetaVar() const
1097 : {
1098 509 : return m_decl.GetMetaVar();
1099 : }
1100 :
1101 : /** Alias for GDALAlgorithmArgDecl::GetType() */
1102 14251 : inline GDALAlgorithmArgType GetType() const
1103 : {
1104 14251 : return m_decl.GetType();
1105 : }
1106 :
1107 : /** Alias for GDALAlgorithmArgDecl::GetCategory() */
1108 1322 : inline const std::string &GetCategory() const
1109 : {
1110 1322 : return m_decl.GetCategory();
1111 : }
1112 :
1113 : /** Alias for GDALAlgorithmArgDecl::IsRequired() */
1114 8332 : inline bool IsRequired() const
1115 : {
1116 8332 : return m_decl.IsRequired();
1117 : }
1118 :
1119 : /** Alias for GDALAlgorithmArgDecl::GetMinCount() */
1120 1466 : inline int GetMinCount() const
1121 : {
1122 1466 : return m_decl.GetMinCount();
1123 : }
1124 :
1125 : /** Alias for GDALAlgorithmArgDecl::GetMaxCount() */
1126 1186 : inline int GetMaxCount() const
1127 : {
1128 1186 : return m_decl.GetMaxCount();
1129 : }
1130 :
1131 : /** Alias for GDALAlgorithmArgDecl::GetDisplayHintAboutRepetition() */
1132 324 : inline bool GetDisplayHintAboutRepetition() const
1133 : {
1134 324 : return m_decl.GetDisplayHintAboutRepetition();
1135 : }
1136 :
1137 : /** Alias for GDALAlgorithmArgDecl::GetPackedValuesAllowed() */
1138 264 : inline bool GetPackedValuesAllowed() const
1139 : {
1140 264 : return m_decl.GetPackedValuesAllowed();
1141 : }
1142 :
1143 : /** Alias for GDALAlgorithmArgDecl::GetRepeatedArgAllowed() */
1144 693 : inline bool GetRepeatedArgAllowed() const
1145 : {
1146 693 : return m_decl.GetRepeatedArgAllowed();
1147 : }
1148 :
1149 : /** Alias for GDALAlgorithmArgDecl::IsPositional() */
1150 1524 : inline bool IsPositional() const
1151 : {
1152 1524 : return m_decl.IsPositional();
1153 : }
1154 :
1155 : /** Alias for GDALAlgorithmArgDecl::GetChoices() */
1156 1007 : inline const std::vector<std::string> &GetChoices() const
1157 : {
1158 1007 : return m_decl.GetChoices();
1159 : }
1160 :
1161 : /** Alias for GDALAlgorithmArgDecl::GetHiddenChoices() */
1162 174 : inline const std::vector<std::string> &GetHiddenChoices() const
1163 : {
1164 174 : return m_decl.GetHiddenChoices();
1165 : }
1166 :
1167 : /** Return auto completion choices, if a auto completion function has been
1168 : * registered.
1169 : */
1170 : inline std::vector<std::string>
1171 30 : GetAutoCompleteChoices(const std::string ¤tValue) const
1172 : {
1173 30 : if (m_autoCompleteFunction)
1174 29 : return m_autoCompleteFunction(currentValue);
1175 1 : return {};
1176 : }
1177 :
1178 : /** Return whether the argument value has been explicitly set with Set() */
1179 31257 : inline bool IsExplicitlySet() const
1180 : {
1181 31257 : return m_explicitlySet;
1182 : }
1183 :
1184 : /** Alias for GDALAlgorithmArgDecl::HasDefaultValue() */
1185 678 : inline bool HasDefaultValue() const
1186 : {
1187 678 : return m_decl.HasDefaultValue();
1188 : }
1189 :
1190 : /** Alias for GDALAlgorithmArgDecl::IsHiddenForCLI() */
1191 1116 : inline bool IsHiddenForCLI() const
1192 : {
1193 1116 : return m_decl.IsHiddenForCLI();
1194 : }
1195 :
1196 : /** Alias for GDALAlgorithmArgDecl::IsOnlyForCLI() */
1197 2449 : inline bool IsOnlyForCLI() const
1198 : {
1199 2449 : return m_decl.IsOnlyForCLI();
1200 : }
1201 :
1202 : /** Alias for GDALAlgorithmArgDecl::IsInput() */
1203 1367 : inline bool IsInput() const
1204 : {
1205 1367 : return m_decl.IsInput();
1206 : }
1207 :
1208 : /** Alias for GDALAlgorithmArgDecl::IsOutput() */
1209 1940 : inline bool IsOutput() const
1210 : {
1211 1940 : return m_decl.IsOutput();
1212 : }
1213 :
1214 : /** Alias for GDALAlgorithmArgDecl::IsReadFromFileAtSyntaxAllowed() */
1215 : inline bool IsReadFromFileAtSyntaxAllowed() const
1216 : {
1217 : return m_decl.IsReadFromFileAtSyntaxAllowed();
1218 : }
1219 :
1220 : /** Alias for GDALAlgorithmArgDecl::IsRemoveSQLCommentsEnabled() */
1221 : inline bool IsRemoveSQLCommentsEnabled() const
1222 : {
1223 : return m_decl.IsRemoveSQLCommentsEnabled();
1224 : }
1225 :
1226 : /** Alias for GDALAlgorithmArgDecl::GetMutualExclusionGroup() */
1227 1730 : inline const std::string &GetMutualExclusionGroup() const
1228 : {
1229 1730 : return m_decl.GetMutualExclusionGroup();
1230 : }
1231 :
1232 : /** Alias for GDALAlgorithmArgDecl::GetMetadata() */
1233 : inline const std::map<std::string, std::vector<std::string>>
1234 433 : GetMetadata() const
1235 : {
1236 433 : return m_decl.GetMetadata();
1237 : }
1238 :
1239 : /** Alias for GDALAlgorithmArgDecl::GetMetadataItem() */
1240 : inline const std::vector<std::string> *
1241 257 : GetMetadataItem(const std::string &name) const
1242 : {
1243 257 : return m_decl.GetMetadataItem(name);
1244 : }
1245 :
1246 : /** Alias for GDALAlgorithmArgDecl::GetDefault() */
1247 73 : template <class T> inline const T &GetDefault() const
1248 : {
1249 73 : return m_decl.GetDefault<T>();
1250 : }
1251 :
1252 : /** Alias for GDALAlgorithmArgDecl::AutoOpenDataset() */
1253 352 : inline bool AutoOpenDataset() const
1254 : {
1255 352 : return m_decl.AutoOpenDataset();
1256 : }
1257 :
1258 : /** Return the value of the argument, which is by decreasing order of priority:
1259 : * - the value set through Set().
1260 : * - the default value set through SetDefault().
1261 : * - the initial value of the C++ variable to which this argument is bound to.
1262 : *
1263 : * Must be called with T consistent of the type of the algorithm:
1264 : * - bool for GAAT_BOOLEAN
1265 : * - int for GAAT_INTEGER
1266 : * - double for GAAT_REAL
1267 : * - std::string for GAAT_STRING
1268 : * - GDALArgDatasetValue for GAAT_DATASET
1269 : * - std::vector<int> for GAAT_INTEGER_LIST
1270 : * - std::vector<double for GAAT_REAL_LIST
1271 : * - std::vector<std::string> for GAAT_STRING_LIST
1272 : * - std::vector<GDALArgDatasetValue> for GAAT_DATASET_LIST
1273 : */
1274 1778 : template <class T> inline T &Get()
1275 : {
1276 1778 : return *(std::get<T *>(m_value));
1277 : }
1278 :
1279 : /** Return the value of the argument, which is by decreasing order of priority:
1280 : * - the value set through Set().
1281 : * - the default value set through SetDefault().
1282 : * - the initial value of the C++ variable to which this argument is bound to.
1283 : *
1284 : * Must be called with T consistent of the type of the algorithm:
1285 : * - bool for GAAT_BOOLEAN
1286 : * - int for GAAT_INTEGER
1287 : * - double for GAAT_REAL
1288 : * - std::string for GAAT_STRING
1289 : * - GDALArgDatasetValue for GAAT_DATASET
1290 : * - std::vector<int> for GAAT_INTEGER_LIST
1291 : * - std::vector<double for GAAT_REAL_LIST
1292 : * - std::vector<std::string> for GAAT_STRING_LIST
1293 : * - std::vector<GDALArgDatasetValue> for GAAT_DATASET_LIST
1294 : */
1295 148 : template <class T> inline const T &Get() const
1296 : {
1297 148 : return *(std::get<T *>(m_value));
1298 : }
1299 :
1300 : /** Set the value for a GAAT_BOOLEAN argument.
1301 : * It cannot be called several times for a given argument.
1302 : * Validation checks and other actions are run.
1303 : * Return true if success.
1304 : */
1305 : bool Set(bool value);
1306 :
1307 : /** Set the value for a GAAT_STRING argument.
1308 : * It cannot be called several times for a given argument.
1309 : * Validation checks and other actions are run.
1310 : * Return true if success.
1311 : */
1312 : bool Set(const std::string &value);
1313 :
1314 : /** Set the value for a GAAT_STRING argument.
1315 : * It cannot be called several times for a given argument.
1316 : * Validation checks and other actions are run.
1317 : * Return true if success.
1318 : */
1319 34 : bool Set(const char *value)
1320 : {
1321 34 : return Set(std::string(value ? value : ""));
1322 : }
1323 :
1324 : /** Set the value for a GAAT_INTEGER (or GAAT_REAL) argument.
1325 : * It cannot be called several times for a given argument.
1326 : * Validation checks and other actions are run.
1327 : * Return true if success.
1328 : */
1329 : bool Set(int value);
1330 :
1331 : /** Set the value for a GAAT_REAL argument */
1332 : bool Set(double value);
1333 :
1334 : /** Set the value for a GAAT_DATASET argument, increasing ds' reference
1335 : * counter if ds is not null.
1336 : * It cannot be called several times for a given argument.
1337 : * Validation checks and other actions are run.
1338 : * Return true if success.
1339 : */
1340 : bool Set(GDALDataset *ds);
1341 :
1342 : /** Set the value for a GAAT_DATASET argument.
1343 : * It cannot be called several times for a given argument.
1344 : * Validation checks and other actions are run.
1345 : * Return true if success.
1346 : */
1347 : bool Set(std::unique_ptr<GDALDataset> ds);
1348 :
1349 : /** Set the value for a GAAT_DATASET argument.
1350 : * It cannot be called several times for a given argument.
1351 : * Validation checks and other actions are run.
1352 : * Return true if success.
1353 : */
1354 : bool SetDatasetName(const std::string &name);
1355 :
1356 : /** Set the value for a GAAT_DATASET argument.
1357 : * It references the dataset pointed by other.m_poDS.
1358 : * It cannot be called several times for a given argument.
1359 : * Validation checks and other actions are run.
1360 : * Return true if success.
1361 : */
1362 : bool SetFrom(const GDALArgDatasetValue &other);
1363 :
1364 : /** Set the value for a GAAT_STRING_LIST argument.
1365 : * It cannot be called several times for a given argument.
1366 : * Validation checks and other actions are run.
1367 : * Return true if success.
1368 : */
1369 : bool Set(const std::vector<std::string> &value);
1370 :
1371 : /** Set the value for a GAAT_INTEGER_LIST argument.
1372 : * It cannot be called several times for a given argument.
1373 : * Validation checks and other actions are run.
1374 : * Return true if success.
1375 : */
1376 : bool Set(const std::vector<int> &value);
1377 :
1378 : /** Set the value for a GAAT_REAL_LIST argument.
1379 : * It cannot be called several times for a given argument.
1380 : * Validation checks and other actions are run.
1381 : * Return true if success.
1382 : */
1383 : bool Set(const std::vector<double> &value);
1384 :
1385 : /** Set the value for a GAAT_DATASET_LIST argument.
1386 : * It cannot be called several times for a given argument.
1387 : * Validation checks and other actions are run.
1388 : * Return true if success.
1389 : */
1390 : bool Set(std::vector<GDALArgDatasetValue> &&value);
1391 :
1392 : /** Set the value for another argument.
1393 : * For GAAT_DATASET, it will reference the dataset pointed by other.m_poDS.
1394 : * It cannot be called several times for a given argument.
1395 : * Validation checks and other actions are run.
1396 : * Return true if success.
1397 : */
1398 : bool SetFrom(const GDALAlgorithmArg &other);
1399 :
1400 : /** Advanced method used to make "gdal info" and "gdal raster|vector info"
1401 : * to avoid re-opening an already opened dataset */
1402 26 : void SetSkipIfAlreadySet(bool skip = true)
1403 : {
1404 26 : m_skipIfAlreadySet = skip;
1405 26 : }
1406 :
1407 : /** Advanced method used to make "gdal info" and "gdal raster|vector info"
1408 : * to avoid re-opening an already opened dataset */
1409 3 : bool SkipIfAlreadySet() const
1410 : {
1411 3 : return m_skipIfAlreadySet;
1412 : }
1413 :
1414 : //! @cond Doxygen_Suppress
1415 559 : void NotifyValueSet()
1416 : {
1417 559 : m_explicitlySet = true;
1418 559 : }
1419 :
1420 : //! @endcond
1421 :
1422 : protected:
1423 : friend class GDALAlgorithm;
1424 : /** Argument declaration */
1425 : GDALAlgorithmArgDecl m_decl;
1426 : /** Pointer to the value */
1427 : std::variant<bool *, std::string *, int *, double *, GDALArgDatasetValue *,
1428 : std::vector<std::string> *, std::vector<int> *,
1429 : std::vector<double> *, std::vector<GDALArgDatasetValue> *>
1430 : m_value{};
1431 : /** Actions */
1432 : std::vector<std::function<void()>> m_actions{};
1433 : /** Validation actions */
1434 : std::vector<std::function<bool()>> m_validationActions{};
1435 : /** Autocompletion function */
1436 : std::function<std::vector<std::string>(const std::string &)>
1437 : m_autoCompleteFunction{};
1438 :
1439 : private:
1440 : bool m_skipIfAlreadySet = false;
1441 : bool m_explicitlySet = false;
1442 :
1443 324 : template <class T> bool SetInternal(const T &value)
1444 : {
1445 324 : m_explicitlySet = true;
1446 324 : *std::get<T *>(m_value) = value;
1447 324 : return RunAllActions();
1448 : }
1449 :
1450 : bool RunAllActions();
1451 : void RunActions();
1452 : bool RunValidationActions();
1453 : };
1454 :
1455 : /************************************************************************/
1456 : /* GDALInConstructionAlgorithmArg */
1457 : /************************************************************************/
1458 :
1459 : //! @cond Doxygen_Suppress
1460 : namespace test_gdal_algorithm
1461 : {
1462 : struct test_gdal_algorithm;
1463 : }
1464 :
1465 : //! @endcond
1466 :
1467 : /** Technical class used by GDALAlgorithm when constructing argument
1468 : * declarations.
1469 : */
1470 : class CPL_DLL GDALInConstructionAlgorithmArg final : public GDALAlgorithmArg
1471 : {
1472 : friend struct test_gdal_algorithm::test_gdal_algorithm;
1473 :
1474 : public:
1475 : /** Constructor */
1476 : template <class T>
1477 11038 : GDALInConstructionAlgorithmArg(GDALAlgorithm *owner,
1478 : const GDALAlgorithmArgDecl &decl, T *pValue)
1479 11038 : : GDALAlgorithmArg(decl, pValue), m_owner(owner)
1480 : {
1481 11038 : }
1482 :
1483 : /** Add a documented alias for the argument */
1484 : GDALInConstructionAlgorithmArg &AddAlias(const std::string &alias);
1485 :
1486 : /** Add a non-documented alias for the argument */
1487 : GDALInConstructionAlgorithmArg &AddHiddenAlias(const std::string &alias);
1488 :
1489 : /** Alias for GDALAlgorithmArgDecl::SetPositional() */
1490 : GDALInConstructionAlgorithmArg &SetPositional();
1491 :
1492 : /** Alias for GDALAlgorithmArgDecl::SetRequired() */
1493 562 : GDALInConstructionAlgorithmArg &SetRequired()
1494 : {
1495 562 : m_decl.SetRequired();
1496 562 : return *this;
1497 : }
1498 :
1499 : /** Alias for GDALAlgorithmArgDecl::SetMetaVar() */
1500 2143 : GDALInConstructionAlgorithmArg &SetMetaVar(const std::string &metaVar)
1501 : {
1502 2143 : m_decl.SetMetaVar(metaVar);
1503 2143 : return *this;
1504 : }
1505 :
1506 : /** Alias for GDALAlgorithmArgDecl::SetCategory() */
1507 6966 : GDALInConstructionAlgorithmArg &SetCategory(const std::string &category)
1508 : {
1509 6966 : m_decl.SetCategory(category);
1510 6966 : return *this;
1511 : }
1512 :
1513 : /** Alias for GDALAlgorithmArgDecl::SetDefault() */
1514 : template <class T>
1515 853 : GDALInConstructionAlgorithmArg &SetDefault(const T &value)
1516 : {
1517 853 : m_decl.SetDefault(value);
1518 : if constexpr (!std::is_same_v<T, GDALArgDatasetValue> &&
1519 : !std::is_same_v<T, std::vector<GDALArgDatasetValue>>)
1520 : {
1521 853 : if (m_decl.HasDefaultValue())
1522 853 : *std::get<T *>(m_value) = value;
1523 : }
1524 853 : return *this;
1525 : }
1526 :
1527 : /** Alias for GDALAlgorithmArgDecl::SetDefault() */
1528 110 : GDALInConstructionAlgorithmArg &SetDefault(const char *value)
1529 : {
1530 110 : return SetDefault(std::string(value));
1531 : }
1532 :
1533 : /** Alias for GDALAlgorithmArgDecl::SetMinCount() */
1534 221 : GDALInConstructionAlgorithmArg &SetMinCount(int count)
1535 : {
1536 221 : m_decl.SetMinCount(count);
1537 221 : return *this;
1538 : }
1539 :
1540 : /** Alias for GDALAlgorithmArgDecl::SetMaxCount() */
1541 149 : GDALInConstructionAlgorithmArg &SetMaxCount(int count)
1542 : {
1543 149 : m_decl.SetMaxCount(count);
1544 149 : return *this;
1545 : }
1546 :
1547 : /** Alias for GDALAlgorithmArgDecl::SetDisplayHintAboutRepetition() */
1548 : GDALInConstructionAlgorithmArg &
1549 132 : SetDisplayHintAboutRepetition(bool displayHint)
1550 : {
1551 132 : m_decl.SetDisplayHintAboutRepetition(displayHint);
1552 132 : return *this;
1553 : }
1554 :
1555 : /** Alias for GDALAlgorithmArgDecl::SetPackedValuesAllowed() */
1556 3 : GDALInConstructionAlgorithmArg &SetPackedValuesAllowed(bool allowed)
1557 : {
1558 3 : m_decl.SetPackedValuesAllowed(allowed);
1559 3 : return *this;
1560 : }
1561 :
1562 : /** Alias for GDALAlgorithmArgDecl::SetRepeatedArgAllowed() */
1563 180 : GDALInConstructionAlgorithmArg &SetRepeatedArgAllowed(bool allowed)
1564 : {
1565 180 : m_decl.SetRepeatedArgAllowed(allowed);
1566 180 : return *this;
1567 : }
1568 :
1569 : /** Alias for GDALAlgorithmArgDecl::SetChoices() */
1570 : template <typename T, typename... U>
1571 154 : GDALInConstructionAlgorithmArg &SetChoices(T &&first, U &&...rest)
1572 : {
1573 154 : m_decl.SetChoices(std::forward<T>(first), std::forward<U>(rest)...);
1574 154 : return *this;
1575 : }
1576 :
1577 : /** Alias for GDALAlgorithmArgDecl::SetHiddenChoices() */
1578 : template <typename T, typename... U>
1579 40 : GDALInConstructionAlgorithmArg &SetHiddenChoices(T &&first, U &&...rest)
1580 : {
1581 40 : m_decl.SetHiddenChoices(std::forward<T>(first),
1582 : std::forward<U>(rest)...);
1583 40 : return *this;
1584 : }
1585 :
1586 : /** Alias for GDALAlgorithmArgDecl::SetHiddenForCLI() */
1587 2523 : GDALInConstructionAlgorithmArg &SetHiddenForCLI(bool hiddenForCLI = true)
1588 : {
1589 2523 : m_decl.SetHiddenForCLI(hiddenForCLI);
1590 2523 : return *this;
1591 : }
1592 :
1593 : /** Alias for GDALAlgorithmArgDecl::SetOnlyForCLI() */
1594 5752 : GDALInConstructionAlgorithmArg &SetOnlyForCLI(bool onlyForCLI = true)
1595 : {
1596 5752 : m_decl.SetOnlyForCLI(onlyForCLI);
1597 5752 : return *this;
1598 : }
1599 :
1600 : /** Alias for GDALAlgorithmArgDecl::SetIsInput() */
1601 401 : GDALInConstructionAlgorithmArg &SetIsInput(bool isInput = true)
1602 : {
1603 401 : m_decl.SetIsInput(isInput);
1604 401 : return *this;
1605 : }
1606 :
1607 : /** Alias for GDALAlgorithmArgDecl::SetIsOutput() */
1608 401 : GDALInConstructionAlgorithmArg &SetIsOutput(bool isOutput = true)
1609 : {
1610 401 : m_decl.SetIsOutput(isOutput);
1611 401 : return *this;
1612 : }
1613 :
1614 : /** Alias for GDALAlgorithmArgDecl::SetReadFromFileAtSyntaxAllowed() */
1615 70 : GDALInConstructionAlgorithmArg &SetReadFromFileAtSyntaxAllowed()
1616 : {
1617 70 : m_decl.SetReadFromFileAtSyntaxAllowed();
1618 70 : return *this;
1619 : }
1620 :
1621 : /** Alias for GDALAlgorithmArgDecl::SetRemoveSQLCommentsEnabled() */
1622 70 : GDALInConstructionAlgorithmArg &SetRemoveSQLCommentsEnabled()
1623 : {
1624 70 : m_decl.SetRemoveSQLCommentsEnabled();
1625 70 : return *this;
1626 : }
1627 :
1628 : /** Alias for GDALAlgorithmArgDecl::SetAutoOpenDataset() */
1629 24 : GDALInConstructionAlgorithmArg &SetAutoOpenDataset(bool autoOpen)
1630 : {
1631 24 : m_decl.SetAutoOpenDataset(autoOpen);
1632 24 : return *this;
1633 : }
1634 :
1635 : /** Alias for GDALAlgorithmArgDecl::SetMutualExclusionGroup() */
1636 : GDALInConstructionAlgorithmArg &
1637 278 : SetMutualExclusionGroup(const std::string &group)
1638 : {
1639 278 : m_decl.SetMutualExclusionGroup(group);
1640 278 : return *this;
1641 : }
1642 :
1643 : /** Alias for GDALAlgorithmArgDecl::AddMetadataItem() */
1644 : GDALInConstructionAlgorithmArg &
1645 662 : AddMetadataItem(const std::string &name,
1646 : const std::vector<std::string> &values)
1647 : {
1648 662 : m_decl.AddMetadataItem(name, values);
1649 662 : return *this;
1650 : }
1651 :
1652 : /** Register an action that is executed, once and exactly once, if the
1653 : * argument is explicitly set, at the latest by the ValidateArguments()
1654 : * method. */
1655 2201 : GDALInConstructionAlgorithmArg &AddAction(std::function<void()> f)
1656 : {
1657 2201 : m_actions.push_back(f);
1658 2201 : return *this;
1659 : }
1660 :
1661 : /** Register an action that is executed, once and exactly once, if the
1662 : * argument is explicitly set, at the latest by the ValidateArguments()
1663 : * method. If the provided function returns false, validation fails. */
1664 1547 : GDALInConstructionAlgorithmArg &AddValidationAction(std::function<bool()> f)
1665 : {
1666 1547 : m_validationActions.push_back(f);
1667 1547 : return *this;
1668 : }
1669 :
1670 : /** Register a function that will return a list of valid choices for
1671 : * the value of the argument. This is typically used for autocompletion.
1672 : */
1673 2138 : GDALInConstructionAlgorithmArg &SetAutoCompleteFunction(
1674 : std::function<std::vector<std::string>(const std::string &)> f)
1675 : {
1676 2138 : m_autoCompleteFunction = std::move(f);
1677 2138 : return *this;
1678 : }
1679 :
1680 : /** Register an action to validate that the argument value is a valid
1681 : * CRS definition.
1682 : * @param noneAllowed Set to true to mean that "null" or "none" are allowed
1683 : * to mean to unset CRS.
1684 : */
1685 : GDALInConstructionAlgorithmArg &SetIsCRSArg(bool noneAllowed = false);
1686 :
1687 : private:
1688 : GDALAlgorithm *const m_owner;
1689 :
1690 : GDALInConstructionAlgorithmArg(const GDALInConstructionAlgorithmArg &) =
1691 : delete;
1692 : GDALInConstructionAlgorithmArg &
1693 : operator=(const GDALInConstructionAlgorithmArg &) = delete;
1694 : };
1695 :
1696 : /************************************************************************/
1697 : /* GDALAlgorithmRegistry */
1698 : /************************************************************************/
1699 :
1700 : /** Registry of GDAL algorithms.
1701 : */
1702 2631 : class CPL_DLL GDALAlgorithmRegistry
1703 : {
1704 : public:
1705 : /** Special value to put in m_aliases to separate public alias from
1706 : * hidden aliases */
1707 : static constexpr const char *HIDDEN_ALIAS_SEPARATOR = "==hide==";
1708 :
1709 : virtual ~GDALAlgorithmRegistry();
1710 :
1711 : /** Algorithm information */
1712 : class AlgInfo
1713 : {
1714 : public:
1715 : /** Algorithm (short) name */
1716 : std::string m_name{};
1717 : /** Aliases */
1718 : std::vector<std::string> m_aliases{};
1719 : /** Creation function */
1720 : std::function<std::unique_ptr<GDALAlgorithm>()> m_creationFunc{};
1721 : };
1722 :
1723 : /** Register the algorithm of type MyAlgorithm.
1724 : */
1725 9397 : template <class MyAlgorithm> bool Register()
1726 : {
1727 18794 : AlgInfo info;
1728 9397 : info.m_name = MyAlgorithm::NAME;
1729 9397 : info.m_aliases = MyAlgorithm::GetAliases();
1730 10158 : info.m_creationFunc = []() -> std::unique_ptr<GDALAlgorithm>
1731 797 : { return std::make_unique<MyAlgorithm>(); };
1732 18794 : return Register(info);
1733 : }
1734 :
1735 : /** Register an algorithm by its AlgInfo structure.
1736 : */
1737 : bool Register(const AlgInfo &info);
1738 :
1739 : /** Get the names of registered algorithms.
1740 : *
1741 : * This only returns the main name of each algorithm, not its potential
1742 : * alternate names.
1743 : */
1744 : std::vector<std::string> GetNames() const;
1745 :
1746 : /** Instantiate an algorithm by its name or one of its alias. */
1747 : virtual std::unique_ptr<GDALAlgorithm>
1748 : Instantiate(const std::string &name) const;
1749 :
1750 : /** Get an algorithm by its name. */
1751 367 : const AlgInfo *GetInfo(const std::string &name) const
1752 : {
1753 367 : auto iter = m_mapNameToInfo.find(name);
1754 367 : return iter != m_mapNameToInfo.end() ? &(iter->second) : nullptr;
1755 : }
1756 :
1757 : /** Returns true if there are no algorithms registered. */
1758 488 : bool empty() const
1759 : {
1760 488 : return m_mapNameToInfo.empty();
1761 : }
1762 :
1763 : private:
1764 : std::map<std::string, AlgInfo> m_mapNameToInfo{};
1765 : std::map<std::string, AlgInfo> m_mapAliasToInfo{};
1766 : std::map<std::string, AlgInfo> m_mapHiddenAliasToInfo{};
1767 : };
1768 :
1769 : /************************************************************************/
1770 : /* GDALAlgorithm */
1771 : /************************************************************************/
1772 :
1773 : /** GDAL algorithm.
1774 : *
1775 : * An algorithm declares its name, description, help URL.
1776 : * It also defined arguments or (mutual exclusion) sub-algorithms.
1777 : *
1778 : * It can be used from the command line with the ParseCommandLineArguments()
1779 : * method, or users can iterate over the available arguments with the GetArgs()
1780 : * or GetArg() method and fill them programmatically with
1781 : * GDALAlgorithmArg::Set().
1782 : *
1783 : * Execution of the algorithm is done with the Run() method.
1784 : *
1785 : * This is an abstract class. Implementations must sub-class it and implement the
1786 : * RunImpl() method.
1787 : */
1788 :
1789 1100 : /* abstract */ class CPL_DLL GDALAlgorithm
1790 : {
1791 : friend struct test_gdal_algorithm::test_gdal_algorithm;
1792 :
1793 : public:
1794 : virtual ~GDALAlgorithm();
1795 :
1796 : /** Get the algorithm name */
1797 304 : const std::string &GetName() const
1798 : {
1799 304 : return m_name;
1800 : }
1801 :
1802 : /** Get the algorithm description (a few sentences at most) */
1803 18 : const std::string &GetDescription() const
1804 : {
1805 18 : return m_description;
1806 : }
1807 :
1808 : /** Get the long algorithm description. May be empty. */
1809 2 : const std::string &GetLongDescription() const
1810 : {
1811 2 : return m_longDescription;
1812 : }
1813 :
1814 : /** Get the algorithm help URL. If starting with '/', it is relative to
1815 : * "https://gdal.org".
1816 : */
1817 : const std::string &GetHelpURL() const
1818 : {
1819 : return m_helpURL;
1820 : }
1821 :
1822 : /** Get the algorithm full URL, resolving relative URLs. */
1823 129 : const std::string &GetHelpFullURL() const
1824 : {
1825 129 : return m_helpFullURL;
1826 : }
1827 :
1828 : /** Returns whether this algorithm has sub-algorithms */
1829 488 : bool HasSubAlgorithms() const
1830 : {
1831 488 : return !m_subAlgRegistry.empty();
1832 : }
1833 :
1834 : /** Get the names of registered algorithms.
1835 : *
1836 : * This only returns the main name of each algorithm, not its potential
1837 : * alternate names.
1838 : */
1839 84 : std::vector<std::string> GetSubAlgorithmNames() const
1840 : {
1841 84 : return m_subAlgRegistry.GetNames();
1842 : }
1843 :
1844 : /** Instantiate an algorithm by its name (or its alias). */
1845 : std::unique_ptr<GDALAlgorithm>
1846 395 : InstantiateSubAlgorithm(const std::string &name) const
1847 : {
1848 395 : auto ret = m_subAlgRegistry.Instantiate(name);
1849 395 : if (ret)
1850 : {
1851 724 : auto childCallPath = m_callPath;
1852 362 : childCallPath.push_back(name);
1853 362 : ret->SetCallPath(childCallPath);
1854 : }
1855 395 : return ret;
1856 : }
1857 :
1858 : /** Return the potential arguments of the algorithm. */
1859 : const std::vector<std::unique_ptr<GDALAlgorithmArg>> &GetArgs() const
1860 : {
1861 : return m_args;
1862 : }
1863 :
1864 : /** Return the potential arguments of the algorithm. */
1865 43 : std::vector<std::unique_ptr<GDALAlgorithmArg>> &GetArgs()
1866 : {
1867 43 : return m_args;
1868 : }
1869 :
1870 : /** Return an argument from its long name, short name or an alias */
1871 2717 : GDALAlgorithmArg *GetArg(const std::string &osName)
1872 : {
1873 : return const_cast<GDALAlgorithmArg *>(
1874 2717 : const_cast<const GDALAlgorithm *>(this)->GetArg(osName));
1875 : }
1876 :
1877 : /** Return an argument from its long name, short name or an alias */
1878 : const GDALAlgorithmArg *GetArg(const std::string &osName) const;
1879 :
1880 : /** Set the calling path to this algorithm.
1881 : *
1882 : * For example the main "gdal" CLI will set the path to the name of its
1883 : * binary before calling ParseCommandLineArguments().
1884 : */
1885 404 : void SetCallPath(const std::vector<std::string> &path)
1886 : {
1887 404 : m_callPath = path;
1888 404 : }
1889 :
1890 : /** Set hint before calling ParseCommandLineArguments() that it must
1891 : * try to be be graceful when possible, e.g. accepting
1892 : * "gdal raster convert in.tif out.tif --co"
1893 : */
1894 29 : void SetParseForAutoCompletion()
1895 : {
1896 29 : m_parseForAutoCompletion = true;
1897 29 : }
1898 :
1899 : /** Parse a command line argument, which does not include the algorithm
1900 : * name, to set the value of corresponding arguments.
1901 : */
1902 : virtual bool
1903 : ParseCommandLineArguments(const std::vector<std::string> &args);
1904 :
1905 : /** Validate that all constraints are met. This method is automatically
1906 : * executed by ParseCommandLineArguments() and Run(), and thus does
1907 : * generally not need to be explicitly called.
1908 : */
1909 : virtual bool ValidateArguments();
1910 :
1911 : /** Execute the algorithm, starting with ValidateArguments() and then
1912 : * calling RunImpl().
1913 : */
1914 : bool Run(GDALProgressFunc pfnProgress = nullptr,
1915 : void *pProgressData = nullptr);
1916 :
1917 : /** Complete any pending actions, and return the final status.
1918 : * This is typically useful for algorithm that generate an output dataset.
1919 : */
1920 : virtual bool Finalize();
1921 :
1922 : /** Usage options */
1923 : struct UsageOptions
1924 : {
1925 : /** Whether this is a pipeline step */
1926 : bool isPipelineStep;
1927 : /** Maximum width of the names of the options */
1928 : size_t maxOptLen;
1929 :
1930 53 : UsageOptions() : isPipelineStep(false), maxOptLen(0)
1931 : {
1932 53 : }
1933 : };
1934 :
1935 : /** Return the usage as a string appropriate for command-line interface
1936 : * --help output.
1937 : */
1938 : virtual std::string
1939 : GetUsageForCLI(bool shortUsage,
1940 : const UsageOptions &usageOptions = UsageOptions()) const;
1941 :
1942 : /** Return the usage of the algorithm as a JSON-serialized string.
1943 : *
1944 : * This can be used to dynamically generate interfaces to algorithms.
1945 : */
1946 : virtual std::string GetUsageAsJSON() const;
1947 :
1948 : /** Return the actual algorithm that is going to be invoked, when the
1949 : * current algorithm has sub-algorithms.
1950 : *
1951 : * Only valid after ParseCommandLineArguments() has been called.
1952 : */
1953 80 : GDALAlgorithm &GetActualAlgorithm()
1954 : {
1955 80 : if (m_selectedSubAlg)
1956 46 : return m_selectedSubAlg->GetActualAlgorithm();
1957 34 : return *this;
1958 : }
1959 :
1960 : /** Whether the --help flag has been specified. */
1961 4 : bool IsHelpRequested() const
1962 : {
1963 4 : return m_helpRequested;
1964 : }
1965 :
1966 : /** Whether the --json-usage flag has been specified. */
1967 1 : bool IsJSONUsageRequested() const
1968 : {
1969 1 : return m_JSONUsageRequested;
1970 : }
1971 :
1972 : /** Whether the --progress flag has been specified. */
1973 34 : bool IsProgressBarRequested() const
1974 : {
1975 34 : if (m_selectedSubAlg)
1976 20 : return m_selectedSubAlg->IsProgressBarRequested();
1977 14 : return m_progressBarRequested;
1978 : }
1979 :
1980 : /** Return alias names (generally short) for the current algorithm. */
1981 1 : const std::vector<std::string> &GetAliases() const
1982 : {
1983 1 : return m_aliases;
1984 : }
1985 :
1986 : /** Used by the "gdal info" special algorithm when it first tries to
1987 : * run "gdal raster info", to inherit from the potential special flags,
1988 : * such as --help or --json-usage, that this later algorithm has received.
1989 : */
1990 43 : bool PropagateSpecialActionTo(GDALAlgorithm *target)
1991 : {
1992 43 : target->m_progressBarRequested = m_progressBarRequested;
1993 43 : if (m_specialActionRequested)
1994 : {
1995 5 : target->m_specialActionRequested = m_specialActionRequested;
1996 5 : target->m_helpRequested = m_helpRequested;
1997 5 : target->m_JSONUsageRequested = m_JSONUsageRequested;
1998 5 : return true;
1999 : }
2000 38 : return false;
2001 : }
2002 :
2003 : /** Return auto completion suggestions */
2004 : virtual std::vector<std::string>
2005 : GetAutoComplete(std::vector<std::string> &args, bool showAllOptions);
2006 :
2007 : protected:
2008 : friend class GDALInConstructionAlgorithmArg;
2009 :
2010 : /** Selected sub-algorithm. Set by ParseCommandLineArguments() when
2011 : * handling over on a sub-algorithm. */
2012 : GDALAlgorithm *m_selectedSubAlg = nullptr;
2013 :
2014 : /** Call path to the current algorithm. For example, for "gdal convert raster",
2015 : * it is ["gdal", "convert"]
2016 : */
2017 : std::vector<std::string> m_callPath{};
2018 :
2019 : /** Long description of the algorithm */
2020 : std::string m_longDescription{};
2021 :
2022 : /** Whether a progress bar is requested (value of --progress argument) */
2023 : bool m_progressBarRequested = false;
2024 :
2025 : friend class GDALVectorPipelineAlgorithm;
2026 : /** Whether ValidateArguments() should be skipped during ParseCommandLineArguments() */
2027 : bool m_skipValidationInParseCommandLine = false;
2028 :
2029 : friend class GDALAlgorithmRegistry; // to set m_aliases
2030 : /** Algorithm alias names */
2031 : std::vector<std::string> m_aliases{};
2032 :
2033 : /** Special processing for an argument of type GAAT_DATASET */
2034 : bool ProcessDatasetArg(GDALAlgorithmArg *arg, GDALAlgorithm *algForOutput);
2035 :
2036 : /** Constructor */
2037 : GDALAlgorithm(const std::string &name, const std::string &description,
2038 : const std::string &helpURL);
2039 :
2040 : /** Register the sub-algorithm of type MyAlgorithm.
2041 : */
2042 1795 : template <class MyAlgorithm> bool RegisterSubAlgorithm()
2043 : {
2044 1795 : return m_subAlgRegistry.Register<MyAlgorithm>();
2045 : }
2046 :
2047 : /** Register a sub-algoritm by its AlgInfo structure.
2048 : */
2049 370 : bool RegisterSubAlgorithm(const GDALAlgorithmRegistry::AlgInfo &info)
2050 : {
2051 370 : return m_subAlgRegistry.Register(info);
2052 : }
2053 :
2054 : /** Add boolean argument. */
2055 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2056 : char chShortName,
2057 : const std::string &helpMessage,
2058 : bool *pValue);
2059 :
2060 : /** Add string argument. */
2061 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2062 : char chShortName,
2063 : const std::string &helpMessage,
2064 : std::string *pValue);
2065 :
2066 : /** Add integer argument. */
2067 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2068 : char chShortName,
2069 : const std::string &helpMessage,
2070 : int *pValue);
2071 :
2072 : /** Add real argument. */
2073 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2074 : char chShortName,
2075 : const std::string &helpMessage,
2076 : double *pValue);
2077 :
2078 : /** Add dataset argument. */
2079 : GDALInConstructionAlgorithmArg &
2080 : AddArg(const std::string &longName, char chShortName,
2081 : const std::string &helpMessage, GDALArgDatasetValue *pValue,
2082 : GDALArgDatasetValueType type = GDAL_OF_RASTER | GDAL_OF_VECTOR |
2083 : GDAL_OF_MULTIDIM_RASTER);
2084 :
2085 : /** Add list of string argument. */
2086 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2087 : char chShortName,
2088 : const std::string &helpMessage,
2089 : std::vector<std::string> *pValue);
2090 :
2091 : /** Add list of integer argument. */
2092 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2093 : char chShortName,
2094 : const std::string &helpMessage,
2095 : std::vector<int> *pValue);
2096 :
2097 : /** Add list of real argument. */
2098 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2099 : char chShortName,
2100 : const std::string &helpMessage,
2101 : std::vector<double> *pValue);
2102 :
2103 : /** Add list of dataset argument. */
2104 : GDALInConstructionAlgorithmArg &
2105 : AddArg(const std::string &longName, char chShortName,
2106 : const std::string &helpMessage,
2107 : std::vector<GDALArgDatasetValue> *pValue,
2108 : GDALArgDatasetValueType type = GDAL_OF_RASTER | GDAL_OF_VECTOR |
2109 : GDAL_OF_MULTIDIM_RASTER);
2110 :
2111 : /** Add input dataset argument. */
2112 : GDALInConstructionAlgorithmArg &
2113 : AddInputDatasetArg(GDALArgDatasetValue *pValue,
2114 : GDALArgDatasetValueType type = GDAL_OF_RASTER |
2115 : GDAL_OF_VECTOR |
2116 : GDAL_OF_MULTIDIM_RASTER,
2117 : bool positionalAndRequired = true);
2118 :
2119 : /** Add input dataset argument. */
2120 : GDALInConstructionAlgorithmArg &
2121 : AddInputDatasetArg(std::vector<GDALArgDatasetValue> *pValue,
2122 : GDALArgDatasetValueType type = GDAL_OF_RASTER |
2123 : GDAL_OF_VECTOR |
2124 : GDAL_OF_MULTIDIM_RASTER,
2125 : bool positionalAndRequired = true);
2126 :
2127 : /** Add open option(s) argument. */
2128 : GDALInConstructionAlgorithmArg &
2129 : AddOpenOptionsArg(std::vector<std::string> *pValue);
2130 :
2131 : /** Add input format(s) argument. */
2132 : GDALInConstructionAlgorithmArg &
2133 : AddInputFormatsArg(std::vector<std::string> *pValue);
2134 :
2135 : /** Add output dataset argument. */
2136 : GDALInConstructionAlgorithmArg &
2137 : AddOutputDatasetArg(GDALArgDatasetValue *pValue,
2138 : GDALArgDatasetValueType type = GDAL_OF_RASTER |
2139 : GDAL_OF_VECTOR |
2140 : GDAL_OF_MULTIDIM_RASTER,
2141 : bool positionalAndRequired = true);
2142 :
2143 : /** Add --overwrite argument. */
2144 : GDALInConstructionAlgorithmArg &AddOverwriteArg(bool *pValue);
2145 :
2146 : /** Add --update argument. */
2147 : GDALInConstructionAlgorithmArg &AddUpdateArg(bool *pValue);
2148 :
2149 : /** Add (non-CLI) output-string argument. */
2150 : GDALInConstructionAlgorithmArg &AddOutputStringArg(std::string *pValue);
2151 :
2152 : /** Add output format argument. */
2153 : GDALInConstructionAlgorithmArg &AddOutputFormatArg(std::string *pValue);
2154 :
2155 : /** Add creation option(s) argument. */
2156 : GDALInConstructionAlgorithmArg &
2157 : AddCreationOptionsArg(std::vector<std::string> *pValue);
2158 :
2159 : /** Add layer creation option(s) argument. */
2160 : GDALInConstructionAlgorithmArg &
2161 : AddLayerCreationOptionsArg(std::vector<std::string> *pValue);
2162 :
2163 : /** Add (single) layer name argument. */
2164 : GDALInConstructionAlgorithmArg &AddLayerNameArg(std::string *pValue);
2165 :
2166 : /** Add (potentially multiple) layer name(s) argument. */
2167 : GDALInConstructionAlgorithmArg &
2168 : AddLayerNameArg(std::vector<std::string> *pValue);
2169 :
2170 : /** Add bbox=xmin,ymin,xmax,ymax argument. */
2171 : GDALInConstructionAlgorithmArg &
2172 : AddBBOXArg(std::vector<double> *pValue, const char *helpMessage = nullptr);
2173 :
2174 : /** Add --progress argument. */
2175 : GDALInConstructionAlgorithmArg &AddProgressArg();
2176 :
2177 : /** Validation function to use for key=value type of arguments. */
2178 : bool ValidateKeyValue(const GDALAlgorithmArg &arg) const;
2179 :
2180 : //! @cond Doxygen_Suppress
2181 : void AddAliasFor(GDALInConstructionAlgorithmArg *arg,
2182 : const std::string &alias);
2183 : void SetPositional(GDALInConstructionAlgorithmArg *arg);
2184 :
2185 : //! @endcond
2186 :
2187 : /** Set whether this algorithm should be reported in JSON usage. */
2188 110 : void SetDisplayInJSONUsage(bool b)
2189 : {
2190 110 : m_displayInJSONUsage = b;
2191 110 : }
2192 :
2193 : //! @cond Doxygen_Suppress
2194 : void ReportError(CPLErr eErrClass, CPLErrorNum err_no, const char *fmt,
2195 : ...) const CPL_PRINT_FUNC_FORMAT(4, 5);
2196 : //! @endcond
2197 :
2198 : /** Return the list of arguments for CLI usage */
2199 : std::pair<std::vector<std::pair<GDALAlgorithmArg *, std::string>>, size_t>
2200 : GetArgNamesForCLI() const;
2201 :
2202 : private:
2203 : const std::string m_name{};
2204 : const std::string m_description{};
2205 : const std::string m_helpURL{};
2206 : const std::string m_helpFullURL{};
2207 : bool m_parsedSubStringAlreadyCalled = false;
2208 : bool m_displayInJSONUsage = true;
2209 : bool m_specialActionRequested = false;
2210 : bool m_helpRequested = false;
2211 : bool m_JSONUsageRequested = false;
2212 : bool m_dummyBoolean = false; // Used for --version
2213 : bool m_parseForAutoCompletion = false;
2214 : std::vector<std::string> m_dummyConfigOptions{};
2215 : std::vector<std::unique_ptr<GDALAlgorithmArg>> m_args{};
2216 : std::map<std::string, GDALAlgorithmArg *> m_mapLongNameToArg{};
2217 : std::map<std::string, GDALAlgorithmArg *> m_mapShortNameToArg{};
2218 : std::vector<GDALAlgorithmArg *> m_positionalArgs{};
2219 : GDALAlgorithmRegistry m_subAlgRegistry{};
2220 : std::unique_ptr<GDALAlgorithm> m_shortCutAlg{};
2221 : std::function<std::vector<std::string>(const std::vector<std::string> &)>
2222 : m_autoCompleteFunction{};
2223 :
2224 : GDALInConstructionAlgorithmArg &
2225 : AddArg(std::unique_ptr<GDALInConstructionAlgorithmArg> arg);
2226 : bool ParseArgument(
2227 : GDALAlgorithmArg *arg, const std::string &name,
2228 : const std::string &value,
2229 : std::map<
2230 : GDALAlgorithmArg *,
2231 : std::variant<std::vector<std::string>, std::vector<int>,
2232 : std::vector<double>, std::vector<GDALArgDatasetValue>>>
2233 : &inConstructionValues);
2234 :
2235 : bool ValidateFormat(const GDALAlgorithmArg &arg) const;
2236 :
2237 : virtual bool RunImpl(GDALProgressFunc pfnProgress, void *pProgressData) = 0;
2238 :
2239 : /** Extract the last option and its potential value from the provided
2240 : * argument list, and remove them from the list.
2241 : */
2242 : void ExtractLastOptionAndValue(std::vector<std::string> &args,
2243 : std::string &option,
2244 : std::string &value) const;
2245 :
2246 : GDALAlgorithm(const GDALAlgorithm &) = delete;
2247 : GDALAlgorithm &operator=(const GDALAlgorithm &) = delete;
2248 : };
2249 :
2250 : //! @cond Doxygen_Suppress
2251 : struct GDALAlgorithmHS
2252 : {
2253 : private:
2254 : std::unique_ptr<GDALAlgorithm> uniquePtr{};
2255 :
2256 : GDALAlgorithmHS(const GDALAlgorithmHS &) = delete;
2257 : GDALAlgorithmHS &operator=(const GDALAlgorithmHS &) = delete;
2258 :
2259 : public:
2260 : GDALAlgorithm *ptr = nullptr;
2261 :
2262 8 : GDALAlgorithmHS() = default;
2263 :
2264 360 : explicit GDALAlgorithmHS(std::unique_ptr<GDALAlgorithm> alg)
2265 360 : : uniquePtr(std::move(alg)), ptr(uniquePtr.get())
2266 : {
2267 360 : }
2268 :
2269 8 : static std::unique_ptr<GDALAlgorithmHS> FromRef(GDALAlgorithm &alg)
2270 : {
2271 8 : auto ret = std::make_unique<GDALAlgorithmHS>();
2272 8 : ret->ptr = &alg;
2273 8 : return ret;
2274 : }
2275 : };
2276 :
2277 : //! @endcond
2278 :
2279 : /************************************************************************/
2280 : /* GDALGlobalAlgorithmRegistry */
2281 : /************************************************************************/
2282 :
2283 : /** Global registry of GDAL algorithms.
2284 : */
2285 : class CPL_DLL GDALGlobalAlgorithmRegistry final : public GDALAlgorithmRegistry
2286 : {
2287 : public:
2288 : /** Name of the root "gdal" algorithm. */
2289 : static constexpr const char *ROOT_ALG_NAME = "gdal";
2290 :
2291 : /** Get the singleton */
2292 : static GDALGlobalAlgorithmRegistry &GetSingleton();
2293 :
2294 : /** Instantiate an algorithm by its name or one of its alias. */
2295 : std::unique_ptr<GDALAlgorithm>
2296 : Instantiate(const std::string &name) const override;
2297 : };
2298 :
2299 : /************************************************************************/
2300 : /* GDAL_STATIC_REGISTER_ALG() */
2301 : /************************************************************************/
2302 :
2303 : /** Static registration of an algorithm by its class name (which must implement
2304 : * GDALAlgorithm)
2305 : */
2306 : #define GDAL_STATIC_REGISTER_ALG(MyAlgorithm) \
2307 : static bool MyAlgorithm##_static_registration = \
2308 : GDALGlobalAlgorithmRegistry::GetSingleton().Register<MyAlgorithm>()
2309 :
2310 : #endif // #if defined(__cplusplus) && !defined(CPL_SUPRESS_CPLUSPLUS) && (defined(DOXYGEN_SKIP) || __cplusplus >= 201703L || _MSC_VER >= 1920)
2311 :
2312 : #endif // GDAL_ALGORITHM_INCLUDED
|