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 : #include "cpl_port.h"
14 : #include "cpl_conv.h"
15 : #include "cpl_error.h"
16 : #include "cpl_json.h"
17 : #include "cpl_minixml.h"
18 :
19 : #include "gdalalgorithm.h"
20 : #include "gdal_priv.h"
21 :
22 : #include <algorithm>
23 : #include <cassert>
24 : #include <cerrno>
25 : #include <cstdlib>
26 : #include <map>
27 :
28 : #ifndef _
29 : #define _(x) (x)
30 : #endif
31 :
32 : constexpr const char *GDAL_ARG_NAME_INPUT_FORMAT = "input-format";
33 :
34 : constexpr const char *GDAL_ARG_NAME_OUTPUT_FORMAT = "output-format";
35 :
36 : constexpr const char *GDAL_ARG_NAME_OPEN_OPTION = "open-option";
37 :
38 : //! @cond Doxygen_Suppress
39 : struct GDALAlgorithmArgHS
40 : {
41 : GDALAlgorithmArg *ptr = nullptr;
42 :
43 324 : explicit GDALAlgorithmArgHS(GDALAlgorithmArg *arg) : ptr(arg)
44 : {
45 324 : }
46 : };
47 :
48 : //! @endcond
49 :
50 : //! @cond Doxygen_Suppress
51 : struct GDALArgDatasetValueHS
52 : {
53 : GDALArgDatasetValue val{};
54 : GDALArgDatasetValue *ptr = nullptr;
55 :
56 1 : GDALArgDatasetValueHS() : ptr(&val)
57 : {
58 1 : }
59 :
60 163 : explicit GDALArgDatasetValueHS(GDALArgDatasetValue *arg) : ptr(arg)
61 : {
62 163 : }
63 :
64 : GDALArgDatasetValueHS(const GDALArgDatasetValueHS &) = delete;
65 : GDALArgDatasetValueHS &operator=(const GDALArgDatasetValueHS &) = delete;
66 : };
67 :
68 : //! @endcond
69 :
70 : /************************************************************************/
71 : /* GDALAlgorithmArgTypeIsList() */
72 : /************************************************************************/
73 :
74 17844 : bool GDALAlgorithmArgTypeIsList(GDALAlgorithmArgType type)
75 : {
76 17844 : switch (type)
77 : {
78 12730 : case GAAT_BOOLEAN:
79 : case GAAT_STRING:
80 : case GAAT_INTEGER:
81 : case GAAT_REAL:
82 : case GAAT_DATASET:
83 12730 : break;
84 :
85 5114 : case GAAT_STRING_LIST:
86 : case GAAT_INTEGER_LIST:
87 : case GAAT_REAL_LIST:
88 : case GAAT_DATASET_LIST:
89 5114 : return true;
90 : }
91 :
92 12730 : return false;
93 : }
94 :
95 : /************************************************************************/
96 : /* GDALAlgorithmArgTypeName() */
97 : /************************************************************************/
98 :
99 605 : const char *GDALAlgorithmArgTypeName(GDALAlgorithmArgType type)
100 : {
101 605 : switch (type)
102 : {
103 145 : case GAAT_BOOLEAN:
104 145 : break;
105 148 : case GAAT_STRING:
106 148 : return "string";
107 9 : case GAAT_INTEGER:
108 9 : return "integer";
109 4 : case GAAT_REAL:
110 4 : return "real";
111 82 : case GAAT_DATASET:
112 82 : return "dataset";
113 155 : case GAAT_STRING_LIST:
114 155 : return "string_list";
115 9 : case GAAT_INTEGER_LIST:
116 9 : return "integer_list";
117 47 : case GAAT_REAL_LIST:
118 47 : return "real_list";
119 6 : case GAAT_DATASET_LIST:
120 6 : return "dataset_list";
121 : }
122 :
123 145 : return "boolean";
124 : }
125 :
126 : /************************************************************************/
127 : /* GDALArgDatasetValueTypeName() */
128 : /************************************************************************/
129 :
130 1000 : std::string GDALArgDatasetValueTypeName(GDALArgDatasetValueType type)
131 : {
132 1000 : std::string ret;
133 1000 : if ((type & GDAL_OF_RASTER) != 0)
134 480 : ret = "raster";
135 1000 : if ((type & GDAL_OF_VECTOR) != 0)
136 : {
137 605 : if (!ret.empty())
138 : {
139 86 : if ((type & GDAL_OF_MULTIDIM_RASTER) != 0)
140 79 : ret += ", ";
141 : else
142 7 : ret += " or ";
143 : }
144 605 : ret += "vector";
145 : }
146 1000 : if ((type & GDAL_OF_MULTIDIM_RASTER) != 0)
147 : {
148 82 : if (!ret.empty())
149 : {
150 81 : ret += " or ";
151 : }
152 82 : ret += "multidimensional raster";
153 : }
154 1000 : return ret;
155 : }
156 :
157 : /************************************************************************/
158 : /* GDALAlgorithmArgDecl() */
159 : /************************************************************************/
160 :
161 : // cppcheck-suppress uninitMemberVar
162 14871 : GDALAlgorithmArgDecl::GDALAlgorithmArgDecl(const std::string &longName,
163 : char chShortName,
164 : const std::string &description,
165 14871 : GDALAlgorithmArgType type)
166 : : m_longName(longName),
167 14871 : m_shortName(chShortName ? std::string(&chShortName, 1) : std::string()),
168 : m_description(description), m_type(type),
169 29742 : m_metaVar(CPLString(m_type == GAAT_BOOLEAN ? std::string() : longName)
170 14871 : .toupper()),
171 44613 : m_maxCount(GDALAlgorithmArgTypeIsList(type) ? UNBOUNDED : 1)
172 : {
173 14871 : if (m_type == GAAT_BOOLEAN)
174 : {
175 8156 : m_defaultValue = false;
176 : }
177 14871 : }
178 :
179 : /************************************************************************/
180 : /* GDALAlgorithmArgDecl::SetMinCount() */
181 : /************************************************************************/
182 :
183 352 : GDALAlgorithmArgDecl &GDALAlgorithmArgDecl::SetMinCount(int count)
184 : {
185 352 : if (!GDALAlgorithmArgTypeIsList(m_type))
186 : {
187 1 : CPLError(CE_Failure, CPLE_NotSupported,
188 : "SetMinCount() illegal on scalar argument '%s'",
189 1 : GetName().c_str());
190 : }
191 : else
192 : {
193 351 : m_minCount = count;
194 : }
195 352 : return *this;
196 : }
197 :
198 : /************************************************************************/
199 : /* GDALAlgorithmArgDecl::SetMaxCount() */
200 : /************************************************************************/
201 :
202 197 : GDALAlgorithmArgDecl &GDALAlgorithmArgDecl::SetMaxCount(int count)
203 : {
204 197 : if (!GDALAlgorithmArgTypeIsList(m_type))
205 : {
206 1 : CPLError(CE_Failure, CPLE_NotSupported,
207 : "SetMaxCount() illegal on scalar argument '%s'",
208 1 : GetName().c_str());
209 : }
210 : else
211 : {
212 196 : m_maxCount = count;
213 : }
214 197 : return *this;
215 : }
216 :
217 : /************************************************************************/
218 : /* GDALAlgorithmArg::Set() */
219 : /************************************************************************/
220 :
221 99 : bool GDALAlgorithmArg::Set(bool value)
222 : {
223 99 : if (m_decl.GetType() != GAAT_BOOLEAN)
224 : {
225 14 : CPLError(
226 : CE_Failure, CPLE_AppDefined,
227 : "Calling Set(bool) on argument '%s' of type %s is not supported",
228 7 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
229 7 : return false;
230 : }
231 92 : return SetInternal(value);
232 : }
233 :
234 204 : bool GDALAlgorithmArg::ProcessString(std::string &value) const
235 : {
236 225 : if (m_decl.IsReadFromFileAtSyntaxAllowed() && !value.empty() &&
237 21 : value.front() == '@')
238 : {
239 2 : GByte *pabyData = nullptr;
240 2 : if (VSIIngestFile(nullptr, value.c_str() + 1, &pabyData, nullptr,
241 2 : 1024 * 1024))
242 : {
243 : // Remove UTF-8 BOM
244 1 : size_t offset = 0;
245 1 : if (pabyData[0] == 0xEF && pabyData[1] == 0xBB &&
246 1 : pabyData[2] == 0xBF)
247 : {
248 1 : offset = 3;
249 : }
250 1 : value = reinterpret_cast<const char *>(pabyData + offset);
251 1 : VSIFree(pabyData);
252 : }
253 : else
254 : {
255 1 : return false;
256 : }
257 : }
258 :
259 203 : if (m_decl.IsRemoveSQLCommentsEnabled())
260 20 : value = CPLRemoveSQLComments(value);
261 :
262 203 : return true;
263 : }
264 :
265 194 : bool GDALAlgorithmArg::Set(const std::string &value)
266 : {
267 194 : if (m_decl.GetType() != GAAT_STRING)
268 : {
269 2 : CPLError(CE_Failure, CPLE_AppDefined,
270 : "Calling Set(std::string) on argument '%s' of type %s is not "
271 : "supported",
272 1 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
273 1 : return false;
274 : }
275 :
276 193 : std::string newValue(value);
277 193 : return ProcessString(newValue) && SetInternal(newValue);
278 : }
279 :
280 18 : bool GDALAlgorithmArg::Set(int value)
281 : {
282 18 : if (m_decl.GetType() == GAAT_REAL)
283 : {
284 2 : return Set(static_cast<double>(value));
285 : }
286 16 : if (m_decl.GetType() != GAAT_INTEGER)
287 : {
288 2 : CPLError(
289 : CE_Failure, CPLE_AppDefined,
290 : "Calling Set(int) on argument '%s' of type %s is not supported",
291 1 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
292 1 : return false;
293 : }
294 15 : return SetInternal(value);
295 : }
296 :
297 6 : bool GDALAlgorithmArg::Set(double value)
298 : {
299 6 : if (m_decl.GetType() != GAAT_REAL)
300 : {
301 2 : CPLError(
302 : CE_Failure, CPLE_AppDefined,
303 : "Calling Set(double) on argument '%s' of type %s is not supported",
304 1 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
305 1 : return false;
306 : }
307 5 : return SetInternal(value);
308 : }
309 :
310 16 : bool GDALAlgorithmArg::Set(GDALDataset *ds)
311 : {
312 16 : if (m_decl.GetType() != GAAT_DATASET)
313 : {
314 2 : CPLError(CE_Failure, CPLE_AppDefined,
315 : "Calling Set(GDALDataset*, bool) on argument '%s' of type %s "
316 : "is not supported",
317 1 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
318 1 : return false;
319 : }
320 15 : auto &val = *std::get<GDALArgDatasetValue *>(m_value);
321 15 : if (val.GetInputFlags() == GADV_NAME && val.GetOutputFlags() == GADV_OBJECT)
322 : {
323 2 : CPLError(
324 : CE_Failure, CPLE_AppDefined,
325 : "Dataset object '%s' is created by algorithm and cannot be set "
326 : "as an input.",
327 2 : GetName().c_str());
328 2 : return false;
329 : }
330 13 : m_explicitlySet = true;
331 13 : val.Set(ds);
332 13 : return RunAllActions();
333 : }
334 :
335 2 : bool GDALAlgorithmArg::Set(std::unique_ptr<GDALDataset> ds)
336 : {
337 2 : if (m_decl.GetType() != GAAT_DATASET)
338 : {
339 2 : CPLError(CE_Failure, CPLE_AppDefined,
340 : "Calling Set(GDALDataset*, bool) on argument '%s' of type %s "
341 : "is not supported",
342 1 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
343 1 : return false;
344 : }
345 1 : auto &val = *std::get<GDALArgDatasetValue *>(m_value);
346 1 : if (val.GetInputFlags() == GADV_NAME && val.GetOutputFlags() == GADV_OBJECT)
347 : {
348 0 : CPLError(
349 : CE_Failure, CPLE_AppDefined,
350 : "Dataset object '%s' is created by algorithm and cannot be set "
351 : "as an input.",
352 0 : GetName().c_str());
353 0 : return false;
354 : }
355 1 : m_explicitlySet = true;
356 1 : val.Set(std::move(ds));
357 1 : return RunAllActions();
358 : }
359 :
360 318 : bool GDALAlgorithmArg::SetDatasetName(const std::string &name)
361 : {
362 318 : if (m_decl.GetType() != GAAT_DATASET)
363 : {
364 2 : CPLError(CE_Failure, CPLE_AppDefined,
365 : "Calling SetDatasetName() on argument '%s' of type %s is "
366 : "not supported",
367 1 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
368 1 : return false;
369 : }
370 317 : m_explicitlySet = true;
371 317 : std::get<GDALArgDatasetValue *>(m_value)->Set(name);
372 317 : return RunAllActions();
373 : }
374 :
375 125 : bool GDALAlgorithmArg::SetFrom(const GDALArgDatasetValue &other)
376 : {
377 125 : if (m_decl.GetType() != GAAT_DATASET)
378 : {
379 2 : CPLError(CE_Failure, CPLE_AppDefined,
380 : "Calling SetFrom() on argument '%s' of type %s is "
381 : "not supported",
382 1 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
383 1 : return false;
384 : }
385 124 : m_explicitlySet = true;
386 124 : std::get<GDALArgDatasetValue *>(m_value)->SetFrom(other);
387 124 : return RunAllActions();
388 : }
389 :
390 143 : bool GDALAlgorithmArg::Set(const std::vector<std::string> &value)
391 : {
392 143 : if (m_decl.GetType() != GAAT_STRING_LIST)
393 : {
394 2 : CPLError(CE_Failure, CPLE_AppDefined,
395 : "Calling Set(const std::vector<std::string> &) on argument "
396 : "'%s' of type %s is not supported",
397 1 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
398 1 : return false;
399 : }
400 :
401 276 : if (m_decl.IsReadFromFileAtSyntaxAllowed() ||
402 134 : m_decl.IsRemoveSQLCommentsEnabled())
403 : {
404 16 : std::vector<std::string> newValue(value);
405 19 : for (auto &s : newValue)
406 : {
407 11 : if (!ProcessString(s))
408 0 : return false;
409 : }
410 8 : return SetInternal(newValue);
411 : }
412 : else
413 : {
414 134 : return SetInternal(value);
415 : }
416 : }
417 :
418 12 : bool GDALAlgorithmArg::Set(const std::vector<int> &value)
419 : {
420 12 : if (m_decl.GetType() != GAAT_INTEGER_LIST)
421 : {
422 2 : CPLError(CE_Failure, CPLE_AppDefined,
423 : "Calling Set(const std::vector<int> &) on argument '%s' of "
424 : "type %s is not supported",
425 1 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
426 1 : return false;
427 : }
428 11 : return SetInternal(value);
429 : }
430 :
431 36 : bool GDALAlgorithmArg::Set(const std::vector<double> &value)
432 : {
433 36 : if (m_decl.GetType() != GAAT_REAL_LIST)
434 : {
435 2 : CPLError(CE_Failure, CPLE_AppDefined,
436 : "Calling Set(const std::vector<double> &) on argument '%s' of "
437 : "type %s is not supported",
438 1 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
439 1 : return false;
440 : }
441 35 : return SetInternal(value);
442 : }
443 :
444 31 : bool GDALAlgorithmArg::Set(std::vector<GDALArgDatasetValue> &&value)
445 : {
446 31 : if (m_decl.GetType() != GAAT_DATASET_LIST)
447 : {
448 2 : CPLError(CE_Failure, CPLE_AppDefined,
449 : "Calling Set(const std::vector<GDALArgDatasetValue> &&) on "
450 : "argument '%s' of type %s is not supported",
451 1 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
452 1 : return false;
453 : }
454 30 : m_explicitlySet = true;
455 30 : *std::get<std::vector<GDALArgDatasetValue> *>(m_value) = std::move(value);
456 30 : return RunAllActions();
457 : }
458 :
459 167 : bool GDALAlgorithmArg::SetFrom(const GDALAlgorithmArg &other)
460 : {
461 167 : if (m_decl.GetType() != other.GetType())
462 : {
463 8 : CPLError(CE_Failure, CPLE_AppDefined,
464 : "Calling SetFrom() on argument '%s' of type %s whereas "
465 : "other argument type is %s is not supported",
466 4 : GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()),
467 : GDALAlgorithmArgTypeName(other.GetType()));
468 4 : return false;
469 : }
470 :
471 163 : switch (m_decl.GetType())
472 : {
473 5 : case GAAT_BOOLEAN:
474 5 : *std::get<bool *>(m_value) = *std::get<bool *>(other.m_value);
475 5 : break;
476 32 : case GAAT_STRING:
477 64 : *std::get<std::string *>(m_value) =
478 32 : *std::get<std::string *>(other.m_value);
479 32 : break;
480 1 : case GAAT_INTEGER:
481 1 : *std::get<int *>(m_value) = *std::get<int *>(other.m_value);
482 1 : break;
483 1 : case GAAT_REAL:
484 1 : *std::get<double *>(m_value) = *std::get<double *>(other.m_value);
485 1 : break;
486 120 : case GAAT_DATASET:
487 120 : return SetFrom(other.Get<GDALArgDatasetValue>());
488 1 : case GAAT_STRING_LIST:
489 2 : *std::get<std::vector<std::string> *>(m_value) =
490 1 : *std::get<std::vector<std::string> *>(other.m_value);
491 1 : break;
492 1 : case GAAT_INTEGER_LIST:
493 2 : *std::get<std::vector<int> *>(m_value) =
494 1 : *std::get<std::vector<int> *>(other.m_value);
495 1 : break;
496 1 : case GAAT_REAL_LIST:
497 2 : *std::get<std::vector<double> *>(m_value) =
498 1 : *std::get<std::vector<double> *>(other.m_value);
499 1 : break;
500 1 : case GAAT_DATASET_LIST:
501 : {
502 1 : std::get<std::vector<GDALArgDatasetValue> *>(m_value)->clear();
503 2 : for (const auto &val :
504 5 : *std::get<std::vector<GDALArgDatasetValue> *>(other.m_value))
505 : {
506 4 : GDALArgDatasetValue v;
507 2 : v.SetFrom(val);
508 2 : std::get<std::vector<GDALArgDatasetValue> *>(m_value)
509 2 : ->push_back(std::move(v));
510 : }
511 1 : break;
512 : }
513 : }
514 43 : m_explicitlySet = true;
515 43 : return RunAllActions();
516 : }
517 :
518 : /************************************************************************/
519 : /* GDALAlgorithmArg::RunAllActions() */
520 : /************************************************************************/
521 :
522 1020 : bool GDALAlgorithmArg::RunAllActions()
523 : {
524 1020 : if (!RunValidationActions())
525 25 : return false;
526 995 : RunActions();
527 995 : return true;
528 : }
529 :
530 : /************************************************************************/
531 : /* GDALAlgorithmArg::RunActions() */
532 : /************************************************************************/
533 :
534 996 : void GDALAlgorithmArg::RunActions()
535 : {
536 1007 : for (const auto &f : m_actions)
537 11 : f();
538 996 : }
539 :
540 : /************************************************************************/
541 : /* GDALAlgorithmArg::RunValidationActions() */
542 : /************************************************************************/
543 :
544 1020 : bool GDALAlgorithmArg::RunValidationActions()
545 : {
546 1194 : for (const auto &f : m_validationActions)
547 : {
548 199 : if (!f())
549 25 : return false;
550 : }
551 995 : return true;
552 : }
553 :
554 : /************************************************************************/
555 : /* GDALInConstructionAlgorithmArg::AddAlias() */
556 : /************************************************************************/
557 :
558 : GDALInConstructionAlgorithmArg &
559 3128 : GDALInConstructionAlgorithmArg::AddAlias(const std::string &alias)
560 : {
561 3128 : m_decl.AddAlias(alias);
562 3128 : if (m_owner)
563 3128 : m_owner->AddAliasFor(this, alias);
564 3128 : return *this;
565 : }
566 :
567 : /************************************************************************/
568 : /* GDALInConstructionAlgorithmArg::AddHiddenAlias() */
569 : /************************************************************************/
570 :
571 : GDALInConstructionAlgorithmArg &
572 537 : GDALInConstructionAlgorithmArg::AddHiddenAlias(const std::string &alias)
573 : {
574 537 : m_decl.AddHiddenAlias(alias);
575 537 : if (m_owner)
576 537 : m_owner->AddAliasFor(this, alias);
577 537 : return *this;
578 : }
579 :
580 : /************************************************************************/
581 : /* GDALInConstructionAlgorithmArg::SetPositional() */
582 : /************************************************************************/
583 :
584 1025 : GDALInConstructionAlgorithmArg &GDALInConstructionAlgorithmArg::SetPositional()
585 : {
586 1025 : m_decl.SetPositional();
587 1025 : if (m_owner)
588 1025 : m_owner->SetPositional(this);
589 1025 : return *this;
590 : }
591 :
592 : /************************************************************************/
593 : /* GDALArgDatasetValue::GDALArgDatasetValue() */
594 : /************************************************************************/
595 :
596 19 : GDALArgDatasetValue::GDALArgDatasetValue(GDALDataset *poDS)
597 38 : : m_poDS(poDS), m_name(m_poDS ? m_poDS->GetDescription() : std::string()),
598 19 : m_nameSet(true)
599 : {
600 19 : if (m_poDS)
601 19 : m_poDS->Reference();
602 19 : }
603 :
604 : /************************************************************************/
605 : /* GDALArgDatasetValue::Set() */
606 : /************************************************************************/
607 :
608 377 : void GDALArgDatasetValue::Set(const std::string &name)
609 : {
610 377 : Close();
611 377 : m_name = name;
612 377 : m_nameSet = true;
613 377 : if (m_ownerArg)
614 373 : m_ownerArg->NotifyValueSet();
615 377 : }
616 :
617 : /************************************************************************/
618 : /* GDALArgDatasetValue::Set() */
619 : /************************************************************************/
620 :
621 211 : void GDALArgDatasetValue::Set(std::unique_ptr<GDALDataset> poDS)
622 : {
623 211 : Close();
624 211 : m_poDS = poDS.release();
625 211 : m_name = m_poDS ? m_poDS->GetDescription() : std::string();
626 211 : m_nameSet = true;
627 211 : if (m_ownerArg)
628 193 : m_ownerArg->NotifyValueSet();
629 211 : }
630 :
631 : /************************************************************************/
632 : /* GDALArgDatasetValue::Set() */
633 : /************************************************************************/
634 :
635 648 : void GDALArgDatasetValue::Set(GDALDataset *poDS)
636 : {
637 648 : Close();
638 648 : m_poDS = poDS;
639 648 : if (m_poDS)
640 590 : m_poDS->Reference();
641 648 : m_name = m_poDS ? m_poDS->GetDescription() : std::string();
642 648 : m_nameSet = true;
643 648 : if (m_ownerArg)
644 428 : m_ownerArg->NotifyValueSet();
645 648 : }
646 :
647 : /************************************************************************/
648 : /* GDALArgDatasetValue::SetFrom() */
649 : /************************************************************************/
650 :
651 126 : void GDALArgDatasetValue::SetFrom(const GDALArgDatasetValue &other)
652 : {
653 126 : Close();
654 126 : m_name = other.m_name;
655 126 : m_nameSet = other.m_nameSet;
656 126 : m_poDS = other.m_poDS;
657 126 : if (m_poDS)
658 63 : m_poDS->Reference();
659 126 : }
660 :
661 : /************************************************************************/
662 : /* GDALArgDatasetValue::~GDALArgDatasetValue() */
663 : /************************************************************************/
664 :
665 1843 : GDALArgDatasetValue::~GDALArgDatasetValue()
666 : {
667 1843 : Close();
668 1843 : }
669 :
670 : /************************************************************************/
671 : /* GDALArgDatasetValue::Close() */
672 : /************************************************************************/
673 :
674 3529 : bool GDALArgDatasetValue::Close()
675 : {
676 3529 : bool ret = true;
677 3529 : if (m_poDS && m_poDS->Dereference() == 0)
678 : {
679 376 : ret = m_poDS->Close() == CE_None;
680 376 : delete m_poDS;
681 : }
682 3529 : m_poDS = nullptr;
683 3529 : return ret;
684 : }
685 :
686 : /************************************************************************/
687 : /* GDALArgDatasetValue::operator=() */
688 : /************************************************************************/
689 :
690 2 : GDALArgDatasetValue &GDALArgDatasetValue::operator=(GDALArgDatasetValue &&other)
691 : {
692 2 : Close();
693 2 : m_poDS = other.m_poDS;
694 2 : m_name = other.m_name;
695 2 : m_nameSet = other.m_nameSet;
696 2 : m_type = other.m_type;
697 2 : m_inputFlags = other.m_inputFlags;
698 2 : m_outputFlags = other.m_outputFlags;
699 2 : other.m_poDS = nullptr;
700 2 : other.m_name.clear();
701 2 : other.m_nameSet = false;
702 2 : return *this;
703 : }
704 :
705 : /************************************************************************/
706 : /* GDALArgDatasetValue::GetDataset() */
707 : /************************************************************************/
708 :
709 45 : GDALDataset *GDALArgDatasetValue::GetDatasetIncreaseRefCount()
710 : {
711 45 : if (m_poDS)
712 44 : m_poDS->Reference();
713 45 : return m_poDS;
714 : }
715 :
716 : /************************************************************************/
717 : /* GDALArgDatasetValue(GDALArgDatasetValue &&other) */
718 : /************************************************************************/
719 :
720 27 : GDALArgDatasetValue::GDALArgDatasetValue(GDALArgDatasetValue &&other)
721 54 : : m_poDS(other.m_poDS), m_name(other.m_name), m_nameSet(other.m_nameSet),
722 27 : m_type(other.m_type), m_inputFlags(other.m_inputFlags),
723 27 : m_outputFlags(other.m_outputFlags)
724 : {
725 27 : other.m_poDS = nullptr;
726 27 : other.m_name.clear();
727 27 : }
728 :
729 : /************************************************************************/
730 : /* GDALInConstructionAlgorithmArg::SetIsCRSArg() */
731 : /************************************************************************/
732 :
733 : GDALInConstructionAlgorithmArg &
734 195 : GDALInConstructionAlgorithmArg::SetIsCRSArg(bool noneAllowed)
735 : {
736 195 : if (GetType() != GAAT_STRING)
737 : {
738 1 : CPLError(CE_Failure, CPLE_AppDefined,
739 : "SetIsCRSArg() can only be called on a String argument");
740 1 : return *this;
741 : }
742 : AddValidationAction(
743 58 : [this, noneAllowed]()
744 : {
745 : const std::string &osVal =
746 : static_cast<const GDALInConstructionAlgorithmArg *>(this)
747 27 : ->Get<std::string>();
748 27 : if (!noneAllowed || (osVal != "none" && osVal != "null"))
749 : {
750 24 : OGRSpatialReference oSRS;
751 24 : if (oSRS.SetFromUserInput(osVal.c_str()) != OGRERR_NONE)
752 : {
753 4 : m_owner->ReportError(CE_Failure, CPLE_AppDefined,
754 : "Invalid value for '%s' argument",
755 4 : GetName().c_str());
756 4 : return false;
757 : }
758 : }
759 23 : return true;
760 194 : });
761 :
762 : SetAutoCompleteFunction(
763 6 : [](const std::string ¤tValue)
764 : {
765 6 : std::vector<std::string> oRet;
766 6 : if (!currentValue.empty())
767 : {
768 : const CPLStringList aosTokens(
769 10 : CSLTokenizeString2(currentValue.c_str(), ":", 0));
770 5 : int nCount = 0;
771 5 : OSRCRSInfo **pCRSList = OSRGetCRSInfoListFromDatabase(
772 : aosTokens[0], nullptr, &nCount);
773 10 : std::string osCode;
774 33050 : for (int i = 0; i < nCount; ++i)
775 : {
776 52872 : if (aosTokens.size() == 1 ||
777 19827 : STARTS_WITH(pCRSList[i]->pszCode, aosTokens[1]))
778 : {
779 13409 : if (oRet.empty())
780 5 : osCode = pCRSList[i]->pszCode;
781 26818 : oRet.push_back(std::string(pCRSList[i]->pszCode)
782 13409 : .append(" -- ")
783 13409 : .append(pCRSList[i]->pszName));
784 : }
785 : }
786 5 : if (oRet.size() == 1)
787 : {
788 : // If there is a single match, remove the name from the suggestion.
789 1 : oRet.clear();
790 1 : oRet.push_back(osCode);
791 : }
792 5 : OSRDestroyCRSInfoList(pCRSList);
793 : }
794 6 : if (oRet.empty())
795 : {
796 : const CPLStringList aosAuthorities(
797 2 : OSRGetAuthorityListFromDatabase());
798 6 : for (const char *pszAuth : cpl::Iterate(aosAuthorities))
799 : {
800 5 : int nCount = 0;
801 5 : OSRCRSInfo **pCRSList = OSRGetCRSInfoListFromDatabase(
802 : pszAuth, nullptr, &nCount);
803 5 : OSRDestroyCRSInfoList(pCRSList);
804 5 : if (nCount)
805 4 : oRet.push_back(std::string(pszAuth).append(":"));
806 : }
807 : }
808 6 : return oRet;
809 194 : });
810 :
811 194 : return *this;
812 : }
813 :
814 : /************************************************************************/
815 : /* GDALAlgorithm::GDALAlgorithm() */
816 : /************************************************************************/
817 :
818 1408 : GDALAlgorithm::GDALAlgorithm(const std::string &name,
819 : const std::string &description,
820 1408 : const std::string &helpURL)
821 : : m_name(name), m_description(description), m_helpURL(helpURL),
822 2816 : m_helpFullURL(!m_helpURL.empty() && m_helpURL[0] == '/'
823 1408 : ? "https://gdal.org" + m_helpURL
824 4077 : : m_helpURL)
825 : {
826 2816 : AddArg("help", 'h', _("Display help message and exit"), &m_helpRequested)
827 1408 : .SetOnlyForCLI()
828 2816 : .SetCategory(GAAC_COMMON)
829 1408 : .AddAction([this]() { m_specialActionRequested = true; });
830 2816 : AddArg("version", 0, _("Display GDAL version and exit"), &m_dummyBoolean)
831 1408 : .SetOnlyForCLI()
832 1408 : .SetCategory(GAAC_COMMON);
833 : AddArg("json-usage", 0, _("Display usage as JSON document and exit"),
834 2816 : &m_JSONUsageRequested)
835 1408 : .SetOnlyForCLI()
836 2816 : .SetCategory(GAAC_COMMON)
837 1408 : .AddAction([this]() { m_specialActionRequested = true; });
838 : AddArg("drivers", 0, _("Display driver list as JSON document and exit"),
839 2816 : &m_dummyBoolean)
840 1408 : .SetOnlyForCLI()
841 1408 : .SetCategory(GAAC_COMMON);
842 2816 : AddArg("config", 0, _("Configuration option"), &m_dummyConfigOptions)
843 2816 : .SetMetaVar("<KEY>=<VALUE>")
844 1408 : .SetOnlyForCLI()
845 1408 : .SetCategory(GAAC_COMMON);
846 1408 : }
847 :
848 : /************************************************************************/
849 : /* GDALAlgorithm::~GDALAlgorithm() */
850 : /************************************************************************/
851 :
852 : GDALAlgorithm::~GDALAlgorithm() = default;
853 :
854 : /************************************************************************/
855 : /* GDALAlgorithm::ParseArgument() */
856 : /************************************************************************/
857 :
858 715 : bool GDALAlgorithm::ParseArgument(
859 : GDALAlgorithmArg *arg, const std::string &name, const std::string &value,
860 : std::map<
861 : GDALAlgorithmArg *,
862 : std::variant<std::vector<std::string>, std::vector<int>,
863 : std::vector<double>, std::vector<GDALArgDatasetValue>>>
864 : &inConstructionValues)
865 : {
866 715 : const bool isListArg = GDALAlgorithmArgTypeIsList(arg->GetType());
867 715 : if (arg->IsExplicitlySet() && !isListArg)
868 : {
869 : // Hack for "gdal info" to be able to pass an opened raster dataset
870 : // by "gdal raster info" to the "gdal vector info" algorithm.
871 3 : if (arg->SkipIfAlreadySet())
872 : {
873 1 : arg->SetSkipIfAlreadySet(false);
874 1 : return true;
875 : }
876 :
877 2 : ReportError(CE_Failure, CPLE_IllegalArg,
878 : "Argument '%s' has already been specified.", name.c_str());
879 2 : return false;
880 : }
881 :
882 739 : if (!arg->GetRepeatedArgAllowed() &&
883 27 : cpl::contains(inConstructionValues, arg))
884 : {
885 1 : ReportError(CE_Failure, CPLE_IllegalArg,
886 : "Argument '%s' has already been specified.", name.c_str());
887 1 : return false;
888 : }
889 :
890 711 : switch (arg->GetType())
891 : {
892 79 : case GAAT_BOOLEAN:
893 : {
894 79 : if (value.empty() || value == "true")
895 77 : return arg->Set(true);
896 2 : else if (value == "false")
897 1 : return arg->Set(false);
898 : else
899 : {
900 1 : ReportError(
901 : CE_Failure, CPLE_IllegalArg,
902 : "Invalid value '%s' for boolean argument '%s'. Should be "
903 : "'true' or 'false'.",
904 : value.c_str(), name.c_str());
905 1 : return false;
906 : }
907 : }
908 :
909 158 : case GAAT_STRING:
910 : {
911 158 : const auto &choices = arg->GetChoices();
912 158 : const auto &hiddenChoices = arg->GetHiddenChoices();
913 185 : if (!choices.empty() &&
914 27 : std::find(choices.begin(), choices.end(), value) ==
915 185 : choices.end() &&
916 2 : std::find(hiddenChoices.begin(), hiddenChoices.end(), value) ==
917 160 : hiddenChoices.end())
918 : {
919 1 : std::string expected;
920 3 : for (const auto &choice : choices)
921 : {
922 2 : if (!expected.empty())
923 1 : expected += ", ";
924 2 : expected += '\'';
925 2 : expected += choice;
926 2 : expected += '\'';
927 : }
928 1 : ReportError(
929 : CE_Failure, CPLE_IllegalArg,
930 : "Invalid value '%s' for string argument '%s'. Should be "
931 : "one among %s.",
932 : value.c_str(), name.c_str(), expected.c_str());
933 1 : return false;
934 : }
935 :
936 157 : return arg->Set(value);
937 : }
938 :
939 7 : case GAAT_INTEGER:
940 : {
941 7 : errno = 0;
942 7 : char *endptr = nullptr;
943 7 : const auto val = std::strtol(value.c_str(), &endptr, 10);
944 6 : if (errno == 0 && endptr &&
945 13 : endptr == value.c_str() + value.size() && val >= INT_MIN &&
946 : val <= INT_MAX)
947 : {
948 4 : return arg->Set(static_cast<int>(val));
949 : }
950 : else
951 : {
952 3 : ReportError(CE_Failure, CPLE_IllegalArg,
953 : "Expected integer value for argument '%s', "
954 : "but got '%s'.",
955 : name.c_str(), value.c_str());
956 3 : return false;
957 : }
958 : }
959 :
960 2 : case GAAT_REAL:
961 : {
962 2 : char *endptr = nullptr;
963 2 : double dfValue = CPLStrtod(value.c_str(), &endptr);
964 2 : if (endptr != value.c_str() + value.size())
965 : {
966 1 : ReportError(
967 : CE_Failure, CPLE_IllegalArg,
968 : "Expected real value for argument '%s', but got '%s'.",
969 : name.c_str(), value.c_str());
970 1 : return false;
971 : }
972 1 : return arg->Set(dfValue);
973 : }
974 :
975 316 : case GAAT_DATASET:
976 : {
977 316 : return arg->SetDatasetName(value);
978 : }
979 :
980 94 : case GAAT_STRING_LIST:
981 : {
982 : const CPLStringList aosTokens(
983 94 : arg->GetPackedValuesAllowed()
984 80 : ? CSLTokenizeString2(value.c_str(), ",", CSLT_HONOURSTRINGS)
985 174 : : CSLAddString(nullptr, value.c_str()));
986 94 : if (!cpl::contains(inConstructionValues, arg))
987 : {
988 71 : inConstructionValues[arg] = std::vector<std::string>();
989 : }
990 : auto &valueVector =
991 94 : std::get<std::vector<std::string>>(inConstructionValues[arg]);
992 94 : const auto &choices = arg->GetChoices();
993 94 : const auto &hiddenChoices = arg->GetHiddenChoices();
994 202 : for (const char *v : aosTokens)
995 : {
996 122 : if (!choices.empty() &&
997 10 : std::find(choices.begin(), choices.end(), v) ==
998 122 : choices.end() &&
999 0 : std::find(hiddenChoices.begin(), hiddenChoices.end(),
1000 116 : value) == hiddenChoices.end())
1001 : {
1002 4 : std::string expected;
1003 10 : for (const auto &choice : choices)
1004 : {
1005 6 : if (!expected.empty())
1006 2 : expected += ", ";
1007 6 : expected += '\'';
1008 6 : expected += choice;
1009 6 : expected += '\'';
1010 : }
1011 4 : ReportError(CE_Failure, CPLE_IllegalArg,
1012 : "Invalid value '%s' for string argument '%s'. "
1013 : "Should be "
1014 : "one among %s.",
1015 : v, name.c_str(), expected.c_str());
1016 4 : return false;
1017 : }
1018 :
1019 108 : valueVector.push_back(v);
1020 : }
1021 90 : break;
1022 : }
1023 :
1024 13 : case GAAT_INTEGER_LIST:
1025 : {
1026 : const CPLStringList aosTokens(
1027 13 : arg->GetPackedValuesAllowed()
1028 13 : ? CSLTokenizeString2(value.c_str(), ",", CSLT_HONOURSTRINGS)
1029 26 : : CSLAddString(nullptr, value.c_str()));
1030 13 : if (!cpl::contains(inConstructionValues, arg))
1031 : {
1032 9 : inConstructionValues[arg] = std::vector<int>();
1033 : }
1034 : auto &valueVector =
1035 13 : std::get<std::vector<int>>(inConstructionValues[arg]);
1036 25 : for (const char *v : aosTokens)
1037 : {
1038 16 : errno = 0;
1039 16 : char *endptr = nullptr;
1040 16 : const auto val = std::strtol(v, &endptr, 10);
1041 16 : if (errno == 0 && endptr && endptr == v + strlen(v) &&
1042 12 : val >= INT_MIN && val <= INT_MAX)
1043 : {
1044 12 : valueVector.push_back(static_cast<int>(val));
1045 : }
1046 : else
1047 : {
1048 4 : ReportError(
1049 : CE_Failure, CPLE_IllegalArg,
1050 : "Expected list of integer value for argument '%s', "
1051 : "but got '%s'.",
1052 : name.c_str(), value.c_str());
1053 4 : return false;
1054 : }
1055 : }
1056 9 : break;
1057 : }
1058 :
1059 30 : case GAAT_REAL_LIST:
1060 : {
1061 : const CPLStringList aosTokens(
1062 30 : arg->GetPackedValuesAllowed()
1063 30 : ? CSLTokenizeString2(value.c_str(), ",", CSLT_HONOURSTRINGS)
1064 60 : : CSLAddString(nullptr, value.c_str()));
1065 30 : if (!cpl::contains(inConstructionValues, arg))
1066 : {
1067 28 : inConstructionValues[arg] = std::vector<double>();
1068 : }
1069 : auto &valueVector =
1070 30 : std::get<std::vector<double>>(inConstructionValues[arg]);
1071 128 : for (const char *v : aosTokens)
1072 : {
1073 100 : char *endptr = nullptr;
1074 100 : double dfValue = CPLStrtod(v, &endptr);
1075 100 : if (endptr != v + strlen(v))
1076 : {
1077 2 : ReportError(
1078 : CE_Failure, CPLE_IllegalArg,
1079 : "Expected list of real value for argument '%s', "
1080 : "but got '%s'.",
1081 : name.c_str(), value.c_str());
1082 2 : return false;
1083 : }
1084 98 : valueVector.push_back(dfValue);
1085 : }
1086 28 : break;
1087 : }
1088 :
1089 12 : case GAAT_DATASET_LIST:
1090 : {
1091 : const CPLStringList aosTokens(
1092 24 : CSLTokenizeString2(value.c_str(), ",", CSLT_HONOURSTRINGS));
1093 12 : if (!cpl::contains(inConstructionValues, arg))
1094 : {
1095 11 : inConstructionValues[arg] = std::vector<GDALArgDatasetValue>();
1096 : }
1097 : auto &valueVector = std::get<std::vector<GDALArgDatasetValue>>(
1098 12 : inConstructionValues[arg]);
1099 24 : for (const char *v : aosTokens)
1100 : {
1101 12 : valueVector.push_back(GDALArgDatasetValue(v));
1102 : }
1103 12 : break;
1104 : }
1105 : }
1106 :
1107 139 : return true;
1108 : }
1109 :
1110 : /************************************************************************/
1111 : /* GDALAlgorithm::ParseCommandLineArguments() */
1112 : /************************************************************************/
1113 :
1114 487 : bool GDALAlgorithm::ParseCommandLineArguments(
1115 : const std::vector<std::string> &args)
1116 : {
1117 487 : if (m_parsedSubStringAlreadyCalled)
1118 : {
1119 1 : ReportError(CE_Failure, CPLE_AppDefined,
1120 : "ParseCommandLineArguments() can only be called once per "
1121 : "instance.");
1122 1 : return false;
1123 : }
1124 486 : m_parsedSubStringAlreadyCalled = true;
1125 :
1126 : // AWS like syntax supported too (not advertized)
1127 486 : if (args.size() == 1 && args[0] == "help")
1128 : {
1129 1 : auto arg = GetArg("help");
1130 1 : assert(arg);
1131 1 : arg->Set(true);
1132 1 : arg->RunActions();
1133 1 : return true;
1134 : }
1135 :
1136 485 : if (HasSubAlgorithms())
1137 : {
1138 29 : if (args.empty())
1139 : {
1140 2 : ReportError(CE_Failure, CPLE_AppDefined, "Missing %s name.",
1141 2 : m_callPath.size() == 1 ? "command" : "subcommand");
1142 2 : return false;
1143 : }
1144 27 : if (!args[0].empty() && args[0][0] == '-')
1145 : {
1146 : // go on argument parsing
1147 : }
1148 : else
1149 : {
1150 24 : m_shortCutAlg = InstantiateSubAlgorithm(args[0]);
1151 24 : if (m_shortCutAlg)
1152 : {
1153 23 : m_selectedSubAlg = m_shortCutAlg.get();
1154 23 : bool bRet = m_selectedSubAlg->ParseCommandLineArguments(
1155 46 : std::vector<std::string>(args.begin() + 1, args.end()));
1156 23 : m_selectedSubAlg->PropagateSpecialActionTo(this);
1157 23 : return bRet;
1158 : }
1159 : else
1160 : {
1161 1 : ReportError(CE_Failure, CPLE_AppDefined,
1162 1 : "Unknown command: '%s'", args[0].c_str());
1163 1 : return false;
1164 : }
1165 : }
1166 : }
1167 :
1168 : std::map<
1169 : GDALAlgorithmArg *,
1170 : std::variant<std::vector<std::string>, std::vector<int>,
1171 : std::vector<double>, std::vector<GDALArgDatasetValue>>>
1172 918 : inConstructionValues;
1173 :
1174 918 : std::vector<std::string> lArgs(args);
1175 1169 : for (size_t i = 0; i < lArgs.size(); /* incremented in loop */)
1176 : {
1177 762 : const auto &strArg = lArgs[i];
1178 762 : GDALAlgorithmArg *arg = nullptr;
1179 762 : std::string name;
1180 762 : std::string value;
1181 762 : bool hasValue = false;
1182 762 : if (strArg.size() >= 2 && strArg[0] == '-' && strArg[1] == '-')
1183 : {
1184 398 : const auto equalPos = strArg.find('=');
1185 796 : name = (equalPos != std::string::npos) ? strArg.substr(0, equalPos)
1186 398 : : strArg;
1187 398 : auto iterArg = m_mapLongNameToArg.find(name.substr(2));
1188 398 : if (iterArg == m_mapLongNameToArg.end())
1189 : {
1190 16 : ReportError(CE_Failure, CPLE_IllegalArg,
1191 : "Long name option '%s' is unknown.", name.c_str());
1192 16 : return false;
1193 : }
1194 382 : arg = iterArg->second;
1195 382 : if (equalPos != std::string::npos)
1196 : {
1197 164 : hasValue = true;
1198 164 : value = strArg.substr(equalPos + 1);
1199 : }
1200 : }
1201 364 : else if (strArg.size() >= 2 && strArg[0] == '-')
1202 : {
1203 16 : if (strArg.size() != 2)
1204 : {
1205 1 : ReportError(
1206 : CE_Failure, CPLE_IllegalArg,
1207 : "Option '%s' not recognized. Should be either a long "
1208 : "option or a one-letter short option.",
1209 : strArg.c_str());
1210 2 : return false;
1211 : }
1212 15 : name = strArg;
1213 15 : auto iterArg = m_mapShortNameToArg.find(name.substr(1));
1214 15 : if (iterArg == m_mapShortNameToArg.end())
1215 : {
1216 1 : ReportError(CE_Failure, CPLE_IllegalArg,
1217 : "Short name option '%s' is unknown.", name.c_str());
1218 1 : return false;
1219 : }
1220 14 : arg = iterArg->second;
1221 : }
1222 : else
1223 : {
1224 348 : ++i;
1225 348 : continue;
1226 : }
1227 396 : assert(arg);
1228 :
1229 396 : if (arg->GetType() == GAAT_BOOLEAN)
1230 : {
1231 80 : if (!hasValue)
1232 : {
1233 77 : hasValue = true;
1234 77 : value = "true";
1235 : }
1236 : }
1237 :
1238 396 : if (!hasValue)
1239 : {
1240 155 : if (i + 1 == lArgs.size())
1241 : {
1242 13 : if (m_parseForAutoCompletion)
1243 : {
1244 12 : lArgs.erase(lArgs.begin() + i);
1245 12 : break;
1246 : }
1247 1 : ReportError(
1248 : CE_Failure, CPLE_IllegalArg,
1249 : "Expected value for argument '%s', but ran short of tokens",
1250 : name.c_str());
1251 1 : return false;
1252 : }
1253 142 : value = lArgs[i + 1];
1254 142 : lArgs.erase(lArgs.begin() + i + 1);
1255 : }
1256 :
1257 383 : if (!ParseArgument(arg, name, value, inConstructionValues))
1258 21 : return false;
1259 :
1260 362 : lArgs.erase(lArgs.begin() + i);
1261 : }
1262 :
1263 419 : if (m_specialActionRequested)
1264 : {
1265 8 : return true;
1266 : }
1267 :
1268 520 : const auto ProcessInConstructionValues = [&inConstructionValues]()
1269 : {
1270 506 : for (auto &[arg, value] : inConstructionValues)
1271 : {
1272 111 : if (arg->GetType() == GAAT_STRING_LIST)
1273 : {
1274 68 : if (!arg->Set(std::get<std::vector<std::string>>(
1275 68 : inConstructionValues[arg])))
1276 : {
1277 14 : return false;
1278 : }
1279 : }
1280 43 : else if (arg->GetType() == GAAT_INTEGER_LIST)
1281 : {
1282 6 : if (!arg->Set(
1283 6 : std::get<std::vector<int>>(inConstructionValues[arg])))
1284 : {
1285 1 : return false;
1286 : }
1287 : }
1288 37 : else if (arg->GetType() == GAAT_REAL_LIST)
1289 : {
1290 26 : if (!arg->Set(std::get<std::vector<double>>(
1291 26 : inConstructionValues[arg])))
1292 : {
1293 6 : return false;
1294 : }
1295 : }
1296 11 : else if (arg->GetType() == GAAT_DATASET_LIST)
1297 : {
1298 11 : if (!arg->Set(
1299 : std::move(std::get<std::vector<GDALArgDatasetValue>>(
1300 11 : inConstructionValues[arg]))))
1301 : {
1302 1 : return false;
1303 : }
1304 : }
1305 : }
1306 395 : return true;
1307 411 : };
1308 :
1309 411 : size_t i = 0;
1310 411 : size_t iCurPosArg = 0;
1311 725 : while (i < lArgs.size() && iCurPosArg < m_positionalArgs.size())
1312 : {
1313 323 : GDALAlgorithmArg *arg = m_positionalArgs[iCurPosArg];
1314 326 : while (arg->IsExplicitlySet())
1315 : {
1316 4 : ++iCurPosArg;
1317 4 : if (iCurPosArg == m_positionalArgs.size())
1318 1 : break;
1319 3 : arg = m_positionalArgs[iCurPosArg];
1320 : }
1321 323 : if (iCurPosArg == m_positionalArgs.size())
1322 : {
1323 1 : break;
1324 : }
1325 353 : if (GDALAlgorithmArgTypeIsList(arg->GetType()) &&
1326 31 : arg->GetMinCount() != arg->GetMaxCount())
1327 : {
1328 26 : if (iCurPosArg == 0)
1329 : {
1330 15 : size_t nCountAtEnd = 0;
1331 27 : for (size_t j = 1; j < m_positionalArgs.size(); j++)
1332 : {
1333 14 : const auto *otherArg = m_positionalArgs[j];
1334 14 : if (GDALAlgorithmArgTypeIsList(otherArg->GetType()))
1335 : {
1336 4 : if (otherArg->GetMinCount() != otherArg->GetMaxCount())
1337 : {
1338 2 : ReportError(
1339 : CE_Failure, CPLE_AppDefined,
1340 : "Ambiguity in definition of positional "
1341 : "argument "
1342 : "'%s' given it has a varying number of values, "
1343 : "but follows argument '%s' which also has a "
1344 : "varying number of values",
1345 1 : otherArg->GetName().c_str(),
1346 1 : arg->GetName().c_str());
1347 1 : ProcessInConstructionValues();
1348 1 : return false;
1349 : }
1350 3 : nCountAtEnd += otherArg->GetMinCount();
1351 : }
1352 : else
1353 : {
1354 10 : if (!otherArg->IsRequired())
1355 : {
1356 2 : ReportError(
1357 : CE_Failure, CPLE_AppDefined,
1358 : "Ambiguity in definition of positional "
1359 : "argument "
1360 : "'%s', given it is not required but follows "
1361 : "argument '%s' which has a varying number of "
1362 : "values",
1363 1 : otherArg->GetName().c_str(),
1364 1 : arg->GetName().c_str());
1365 1 : ProcessInConstructionValues();
1366 1 : return false;
1367 : }
1368 9 : nCountAtEnd++;
1369 : }
1370 : }
1371 13 : if (lArgs.size() < nCountAtEnd)
1372 : {
1373 1 : ReportError(CE_Failure, CPLE_AppDefined,
1374 : "Not enough positional values.");
1375 1 : ProcessInConstructionValues();
1376 1 : return false;
1377 : }
1378 29 : for (; i < lArgs.size() - nCountAtEnd; ++i)
1379 : {
1380 18 : if (!ParseArgument(arg, arg->GetName().c_str(), lArgs[i],
1381 : inConstructionValues))
1382 : {
1383 1 : ProcessInConstructionValues();
1384 1 : return false;
1385 : }
1386 : }
1387 : }
1388 11 : else if (iCurPosArg == m_positionalArgs.size() - 1)
1389 : {
1390 24 : for (; i < lArgs.size(); ++i)
1391 : {
1392 15 : if (!ParseArgument(arg, arg->GetName().c_str(), lArgs[i],
1393 : inConstructionValues))
1394 : {
1395 1 : ProcessInConstructionValues();
1396 1 : return false;
1397 : }
1398 : }
1399 : }
1400 : else
1401 : {
1402 1 : ReportError(CE_Failure, CPLE_AppDefined,
1403 : "Ambiguity in definition of positional arguments: "
1404 : "arguments with varying number of values must be "
1405 : "first or last one.");
1406 1 : return false;
1407 : }
1408 : }
1409 : else
1410 : {
1411 296 : if (lArgs.size() - i < static_cast<size_t>(arg->GetMaxCount()))
1412 : {
1413 1 : ReportError(CE_Failure, CPLE_AppDefined,
1414 : "Not enough positional values.");
1415 1 : return false;
1416 : }
1417 295 : const size_t iMax = i + arg->GetMaxCount();
1418 593 : for (; i < iMax; ++i)
1419 : {
1420 299 : if (!ParseArgument(arg, arg->GetName().c_str(), lArgs[i],
1421 : inConstructionValues))
1422 : {
1423 1 : ProcessInConstructionValues();
1424 1 : return false;
1425 : }
1426 : }
1427 : }
1428 314 : ++iCurPosArg;
1429 : }
1430 :
1431 403 : if (i < lArgs.size())
1432 : {
1433 3 : ReportError(CE_Failure, CPLE_AppDefined,
1434 : "Positional values starting at '%s' are not expected.",
1435 3 : lArgs[i].c_str());
1436 3 : ProcessInConstructionValues();
1437 3 : return false;
1438 : }
1439 502 : if (iCurPosArg < m_positionalArgs.size() &&
1440 102 : (GDALAlgorithmArgTypeIsList(m_positionalArgs[iCurPosArg]->GetType())
1441 8 : ? m_positionalArgs[iCurPosArg]->GetMinCount() > 0
1442 94 : : m_positionalArgs[iCurPosArg]->IsRequired()))
1443 : {
1444 274 : while (iCurPosArg < m_positionalArgs.size() &&
1445 108 : m_positionalArgs[iCurPosArg]->IsExplicitlySet())
1446 : {
1447 86 : ++iCurPosArg;
1448 : }
1449 80 : if (iCurPosArg < m_positionalArgs.size())
1450 : {
1451 22 : ReportError(CE_Failure, CPLE_AppDefined,
1452 : "Positional arguments starting at '%s' have not been "
1453 : "specified.",
1454 22 : m_positionalArgs[iCurPosArg]->GetMetaVar().c_str());
1455 22 : ProcessInConstructionValues();
1456 22 : return false;
1457 : }
1458 : }
1459 :
1460 742 : return ProcessInConstructionValues() &&
1461 742 : (m_skipValidationInParseCommandLine || ValidateArguments());
1462 : }
1463 :
1464 : /************************************************************************/
1465 : /* GDALAlgorithm::ReportError() */
1466 : /************************************************************************/
1467 :
1468 : //! @cond Doxygen_Suppress
1469 148 : void GDALAlgorithm::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
1470 : const char *fmt, ...) const
1471 : {
1472 : va_list args;
1473 148 : va_start(args, fmt);
1474 148 : CPLError(eErrClass, err_no, "%s",
1475 148 : std::string(m_name)
1476 148 : .append(": ")
1477 296 : .append(CPLString().vPrintf(fmt, args))
1478 : .c_str());
1479 148 : va_end(args);
1480 148 : }
1481 :
1482 : //! @endcond
1483 :
1484 : /************************************************************************/
1485 : /* GDALAlgorithm::ProcessDatasetArg() */
1486 : /************************************************************************/
1487 :
1488 924 : bool GDALAlgorithm::ProcessDatasetArg(GDALAlgorithmArg *arg,
1489 : GDALAlgorithm *algForOutput)
1490 : {
1491 924 : bool ret = true;
1492 :
1493 924 : const auto updateArg = algForOutput->GetArg(GDAL_ARG_NAME_UPDATE);
1494 1376 : const bool update = (updateArg && updateArg->GetType() == GAAT_BOOLEAN &&
1495 452 : updateArg->Get<bool>());
1496 924 : const auto overwriteArg = algForOutput->GetArg("overwrite");
1497 : const bool overwrite =
1498 1693 : (arg->IsOutput() && overwriteArg &&
1499 1693 : overwriteArg->GetType() == GAAT_BOOLEAN && overwriteArg->Get<bool>());
1500 924 : auto outputArg = algForOutput->GetArg(GDAL_ARG_NAME_OUTPUT);
1501 924 : auto &val = arg->Get<GDALArgDatasetValue>();
1502 924 : if (!val.GetDatasetRef() && !val.IsNameSet())
1503 : {
1504 2 : ReportError(CE_Failure, CPLE_AppDefined,
1505 : "Argument '%s' has no dataset object or dataset name.",
1506 2 : arg->GetName().c_str());
1507 2 : ret = false;
1508 : }
1509 1458 : else if (!val.GetDatasetRef() && arg->AutoOpenDataset() &&
1510 536 : (!arg->IsOutput() || (arg == outputArg && update && !overwrite)))
1511 : {
1512 165 : int flags = val.GetType();
1513 165 : bool assignToOutputArg = false;
1514 :
1515 : // Check if input and output parameters point to the same
1516 : // filename (for vector datasets)
1517 314 : if (arg->GetName() == GDAL_ARG_NAME_INPUT && update && !overwrite &&
1518 314 : outputArg && outputArg->GetType() == GAAT_DATASET)
1519 : {
1520 4 : auto &outputVal = outputArg->Get<GDALArgDatasetValue>();
1521 8 : if (!outputVal.GetDatasetRef() &&
1522 8 : outputVal.GetName() == val.GetName() &&
1523 1 : (outputVal.GetInputFlags() & GADV_OBJECT) != 0)
1524 : {
1525 1 : assignToOutputArg = true;
1526 1 : flags |= GDAL_OF_UPDATE | GDAL_OF_VERBOSE_ERROR;
1527 : }
1528 : }
1529 :
1530 165 : if (!arg->IsOutput() || val.GetInputFlags() == GADV_NAME)
1531 162 : flags |= GDAL_OF_VERBOSE_ERROR;
1532 165 : if ((arg == outputArg || !outputArg) && update)
1533 4 : flags |= GDAL_OF_UPDATE | GDAL_OF_VERBOSE_ERROR;
1534 :
1535 165 : const auto readOnlyArg = algForOutput->GetArg(GDAL_ARG_NAME_READ_ONLY);
1536 : const bool readOnly =
1537 168 : (readOnlyArg && readOnlyArg->GetType() == GAAT_BOOLEAN &&
1538 3 : readOnlyArg->Get<bool>());
1539 165 : if (readOnly)
1540 2 : flags &= ~GDAL_OF_UPDATE;
1541 :
1542 330 : CPLStringList aosOpenOptions;
1543 330 : CPLStringList aosAllowedDrivers;
1544 165 : if (arg->GetName() == GDAL_ARG_NAME_INPUT)
1545 : {
1546 149 : const auto ooArg = GetArg(GDAL_ARG_NAME_OPEN_OPTION);
1547 149 : if (ooArg && ooArg->GetType() == GAAT_STRING_LIST)
1548 : aosOpenOptions =
1549 146 : CPLStringList(ooArg->Get<std::vector<std::string>>());
1550 :
1551 149 : const auto ifArg = GetArg(GDAL_ARG_NAME_INPUT_FORMAT);
1552 149 : if (ifArg && ifArg->GetType() == GAAT_STRING_LIST)
1553 : aosAllowedDrivers =
1554 146 : CPLStringList(ifArg->Get<std::vector<std::string>>());
1555 : }
1556 :
1557 : auto poDS =
1558 165 : GDALDataset::Open(val.GetName().c_str(), flags,
1559 165 : aosAllowedDrivers.List(), aosOpenOptions.List());
1560 165 : if (poDS)
1561 : {
1562 150 : if (assignToOutputArg)
1563 : {
1564 : // Avoid opening twice the same datasource if it is both
1565 : // the input and output.
1566 : // Known to cause problems with at least FGdb, SQLite
1567 : // and GPKG drivers. See #4270
1568 : // Restrict to those 3 drivers. For example it is known
1569 : // to break with the PG driver due to the way it
1570 : // manages transactions.
1571 1 : auto poDriver = poDS->GetDriver();
1572 2 : if (poDriver && (EQUAL(poDriver->GetDescription(), "FileGDB") ||
1573 1 : EQUAL(poDriver->GetDescription(), "SQLite") ||
1574 1 : EQUAL(poDriver->GetDescription(), "GPKG")))
1575 : {
1576 1 : outputArg->Get<GDALArgDatasetValue>().Set(poDS);
1577 : }
1578 : }
1579 150 : val.Set(poDS);
1580 150 : poDS->ReleaseRef();
1581 : }
1582 : else
1583 : {
1584 15 : ret = false;
1585 : }
1586 : }
1587 924 : return ret;
1588 : }
1589 :
1590 : /************************************************************************/
1591 : /* GDALAlgorithm::ValidateArguments() */
1592 : /************************************************************************/
1593 :
1594 845 : bool GDALAlgorithm::ValidateArguments()
1595 : {
1596 845 : if (m_selectedSubAlg)
1597 3 : return m_selectedSubAlg->ValidateArguments();
1598 :
1599 842 : if (m_specialActionRequested)
1600 1 : return true;
1601 :
1602 841 : bool ret = true;
1603 841 : std::map<std::string, std::string> mutualExclusionGroupUsed;
1604 12649 : for (auto &arg : m_args)
1605 : {
1606 : // Check mutually exclusive arguments
1607 11808 : if (arg->IsExplicitlySet())
1608 : {
1609 1569 : const auto &mutualExclusionGroup = arg->GetMutualExclusionGroup();
1610 1569 : if (!mutualExclusionGroup.empty())
1611 : {
1612 : auto oIter =
1613 108 : mutualExclusionGroupUsed.find(mutualExclusionGroup);
1614 108 : if (oIter != mutualExclusionGroupUsed.end())
1615 : {
1616 1 : ret = false;
1617 2 : ReportError(
1618 : CE_Failure, CPLE_AppDefined,
1619 : "Argument '%s' is mutually exclusive with '%s'.",
1620 2 : arg->GetName().c_str(), oIter->second.c_str());
1621 : }
1622 : else
1623 : {
1624 107 : mutualExclusionGroupUsed[mutualExclusionGroup] =
1625 214 : arg->GetName();
1626 : }
1627 : }
1628 : }
1629 :
1630 11814 : if (arg->IsRequired() && !arg->IsExplicitlySet() &&
1631 6 : !arg->HasDefaultValue())
1632 : {
1633 6 : ReportError(CE_Failure, CPLE_AppDefined,
1634 : "Required argument '%s' has not been specified.",
1635 6 : arg->GetName().c_str());
1636 6 : ret = false;
1637 : }
1638 11802 : else if (arg->IsExplicitlySet() && arg->GetType() == GAAT_DATASET)
1639 : {
1640 868 : if (!ProcessDatasetArg(arg.get(), this))
1641 16 : ret = false;
1642 : }
1643 11635 : else if (arg->IsExplicitlySet() &&
1644 701 : GDALAlgorithmArgTypeIsList(arg->GetType()))
1645 : {
1646 267 : int valueCount = 0;
1647 267 : if (arg->GetType() == GAAT_STRING_LIST)
1648 : {
1649 177 : valueCount = static_cast<int>(
1650 177 : arg->Get<std::vector<std::string>>().size());
1651 : }
1652 90 : else if (arg->GetType() == GAAT_INTEGER_LIST)
1653 : {
1654 8 : valueCount =
1655 8 : static_cast<int>(arg->Get<std::vector<int>>().size());
1656 : }
1657 82 : else if (arg->GetType() == GAAT_REAL_LIST)
1658 : {
1659 47 : valueCount =
1660 47 : static_cast<int>(arg->Get<std::vector<double>>().size());
1661 : }
1662 35 : else if (arg->GetType() == GAAT_DATASET_LIST)
1663 : {
1664 35 : valueCount = static_cast<int>(
1665 35 : arg->Get<std::vector<GDALArgDatasetValue>>().size());
1666 : }
1667 :
1668 398 : if (valueCount != arg->GetMinCount() &&
1669 131 : arg->GetMinCount() == arg->GetMaxCount())
1670 : {
1671 2 : ReportError(
1672 : CE_Failure, CPLE_AppDefined,
1673 : "%d value(s) have been specified for argument '%s', "
1674 : "whereas exactly %d were expected.",
1675 1 : valueCount, arg->GetName().c_str(), arg->GetMinCount());
1676 1 : ret = false;
1677 : }
1678 266 : else if (valueCount < arg->GetMinCount())
1679 : {
1680 4 : ReportError(
1681 : CE_Failure, CPLE_AppDefined,
1682 : "Only %d value(s) have been specified for argument '%s', "
1683 : "whereas at least %d were expected.",
1684 2 : valueCount, arg->GetName().c_str(), arg->GetMinCount());
1685 2 : ret = false;
1686 : }
1687 264 : else if (valueCount > arg->GetMaxCount())
1688 : {
1689 2 : ReportError(CE_Failure, CPLE_AppDefined,
1690 : "%d values have been specified for argument '%s', "
1691 : "whereas at most %d were expected.",
1692 1 : valueCount, arg->GetName().c_str(),
1693 : arg->GetMaxCount());
1694 1 : ret = false;
1695 : }
1696 : }
1697 :
1698 11843 : if (arg->IsExplicitlySet() && arg->GetType() == GAAT_DATASET_LIST &&
1699 35 : arg->AutoOpenDataset())
1700 : {
1701 4 : auto &listVal = arg->Get<std::vector<GDALArgDatasetValue>>();
1702 8 : for (auto &val : listVal)
1703 : {
1704 4 : if (!val.GetDatasetRef() && val.GetName().empty())
1705 : {
1706 1 : ReportError(
1707 : CE_Failure, CPLE_AppDefined,
1708 : "Argument '%s' has no dataset object or dataset name.",
1709 1 : arg->GetName().c_str());
1710 1 : ret = false;
1711 : }
1712 3 : else if (!val.GetDatasetRef())
1713 : {
1714 3 : int flags = val.GetType() | GDAL_OF_VERBOSE_ERROR;
1715 :
1716 6 : CPLStringList aosOpenOptions;
1717 6 : CPLStringList aosAllowedDrivers;
1718 3 : if (arg->GetName() == GDAL_ARG_NAME_INPUT)
1719 : {
1720 1 : const auto ooArg = GetArg(GDAL_ARG_NAME_OPEN_OPTION);
1721 1 : if (ooArg && ooArg->GetType() == GAAT_STRING_LIST)
1722 : {
1723 1 : aosOpenOptions = CPLStringList(
1724 1 : ooArg->Get<std::vector<std::string>>());
1725 : }
1726 :
1727 1 : const auto ifArg = GetArg(GDAL_ARG_NAME_INPUT_FORMAT);
1728 1 : if (ifArg && ifArg->GetType() == GAAT_STRING_LIST)
1729 : {
1730 1 : aosAllowedDrivers = CPLStringList(
1731 1 : ifArg->Get<std::vector<std::string>>());
1732 : }
1733 :
1734 1 : const auto updateArg = GetArg(GDAL_ARG_NAME_UPDATE);
1735 2 : if (updateArg && updateArg->GetType() == GAAT_BOOLEAN &&
1736 1 : updateArg->Get<bool>())
1737 : {
1738 1 : flags |= GDAL_OF_UPDATE;
1739 : }
1740 : }
1741 :
1742 : auto poDS = std::unique_ptr<GDALDataset>(GDALDataset::Open(
1743 3 : val.GetName().c_str(), flags, aosAllowedDrivers.List(),
1744 9 : aosOpenOptions.List()));
1745 3 : if (poDS)
1746 : {
1747 2 : val.Set(std::move(poDS));
1748 : }
1749 : else
1750 : {
1751 1 : ret = false;
1752 : }
1753 : }
1754 : }
1755 : }
1756 : }
1757 841 : return ret;
1758 : }
1759 :
1760 : /************************************************************************/
1761 : /* GDALAlgorithm::GetArg() */
1762 : /************************************************************************/
1763 :
1764 5340 : const GDALAlgorithmArg *GDALAlgorithm::GetArg(const std::string &osName) const
1765 : {
1766 5340 : const auto nPos = osName.find_first_not_of('-');
1767 5340 : if (nPos == std::string::npos)
1768 8 : return nullptr;
1769 10664 : const std::string osKey = osName.substr(nPos);
1770 : {
1771 5332 : const auto oIter = m_mapLongNameToArg.find(osKey);
1772 5332 : if (oIter != m_mapLongNameToArg.end())
1773 4099 : return oIter->second;
1774 : }
1775 : {
1776 1233 : const auto oIter = m_mapShortNameToArg.find(osKey);
1777 1233 : if (oIter != m_mapShortNameToArg.end())
1778 2 : return oIter->second;
1779 : }
1780 1231 : return nullptr;
1781 : }
1782 :
1783 : /************************************************************************/
1784 : /* GDALAlgorithm::AddAliasFor() */
1785 : /************************************************************************/
1786 :
1787 : //! @cond Doxygen_Suppress
1788 3665 : void GDALAlgorithm::AddAliasFor(GDALInConstructionAlgorithmArg *arg,
1789 : const std::string &alias)
1790 : {
1791 3665 : if (cpl::contains(m_mapLongNameToArg, alias))
1792 : {
1793 1 : ReportError(CE_Failure, CPLE_AppDefined, "Name '%s' already declared.",
1794 : alias.c_str());
1795 : }
1796 : else
1797 : {
1798 3664 : m_mapLongNameToArg[alias] = arg;
1799 : }
1800 3665 : }
1801 :
1802 : //! @endcond
1803 :
1804 : /************************************************************************/
1805 : /* GDALAlgorithm::SetPositional() */
1806 : /************************************************************************/
1807 :
1808 : //! @cond Doxygen_Suppress
1809 1025 : void GDALAlgorithm::SetPositional(GDALInConstructionAlgorithmArg *arg)
1810 : {
1811 1025 : CPLAssert(std::find(m_positionalArgs.begin(), m_positionalArgs.end(),
1812 : arg) == m_positionalArgs.end());
1813 1025 : m_positionalArgs.push_back(arg);
1814 1025 : }
1815 :
1816 : //! @endcond
1817 :
1818 : /************************************************************************/
1819 : /* GDALAlgorithm::AddArg() */
1820 : /************************************************************************/
1821 :
1822 : GDALInConstructionAlgorithmArg &
1823 14843 : GDALAlgorithm::AddArg(std::unique_ptr<GDALInConstructionAlgorithmArg> arg)
1824 : {
1825 14843 : auto argRaw = arg.get();
1826 14843 : const auto &longName = argRaw->GetName();
1827 14843 : if (!longName.empty())
1828 : {
1829 14840 : if (longName[0] == '-')
1830 : {
1831 1 : ReportError(CE_Failure, CPLE_AppDefined,
1832 : "Long name '%s' should not start with '-'",
1833 : longName.c_str());
1834 : }
1835 14840 : if (longName.find('=') != std::string::npos)
1836 : {
1837 1 : ReportError(CE_Failure, CPLE_AppDefined,
1838 : "Long name '%s' should not contain a '=' character",
1839 : longName.c_str());
1840 : }
1841 14840 : if (cpl::contains(m_mapLongNameToArg, longName))
1842 : {
1843 1 : ReportError(CE_Failure, CPLE_AppDefined,
1844 : "Long name '%s' already declared", longName.c_str());
1845 : }
1846 14840 : m_mapLongNameToArg[longName] = argRaw;
1847 : }
1848 14843 : const auto &shortName = argRaw->GetShortName();
1849 14843 : if (!shortName.empty())
1850 : {
1851 7268 : if (shortName.size() != 1 ||
1852 3634 : !((shortName[0] >= 'a' && shortName[0] <= 'z') ||
1853 3 : (shortName[0] >= 'A' && shortName[0] <= 'Z') ||
1854 2 : (shortName[0] >= '0' && shortName[0] <= '9')))
1855 : {
1856 1 : ReportError(CE_Failure, CPLE_AppDefined,
1857 : "Short name '%s' should be a single letter or digit",
1858 : shortName.c_str());
1859 : }
1860 3634 : if (cpl::contains(m_mapShortNameToArg, shortName))
1861 : {
1862 1 : ReportError(CE_Failure, CPLE_AppDefined,
1863 : "Short name '%s' already declared", shortName.c_str());
1864 : }
1865 3634 : m_mapShortNameToArg[shortName] = argRaw;
1866 : }
1867 14843 : m_args.emplace_back(std::move(arg));
1868 : return *(
1869 14843 : static_cast<GDALInConstructionAlgorithmArg *>(m_args.back().get()));
1870 : }
1871 :
1872 : GDALInConstructionAlgorithmArg &
1873 8152 : GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
1874 : const std::string &helpMessage, bool *pValue)
1875 : {
1876 8152 : return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
1877 : this,
1878 16304 : GDALAlgorithmArgDecl(longName, chShortName, helpMessage, GAAT_BOOLEAN),
1879 16304 : pValue));
1880 : }
1881 :
1882 : GDALInConstructionAlgorithmArg &
1883 1650 : GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
1884 : const std::string &helpMessage, std::string *pValue)
1885 : {
1886 1650 : return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
1887 : this,
1888 3300 : GDALAlgorithmArgDecl(longName, chShortName, helpMessage, GAAT_STRING),
1889 3300 : pValue));
1890 : }
1891 :
1892 : GDALInConstructionAlgorithmArg &
1893 66 : GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
1894 : const std::string &helpMessage, int *pValue)
1895 : {
1896 66 : return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
1897 : this,
1898 132 : GDALAlgorithmArgDecl(longName, chShortName, helpMessage, GAAT_INTEGER),
1899 132 : pValue));
1900 : }
1901 :
1902 : GDALInConstructionAlgorithmArg &
1903 4 : GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
1904 : const std::string &helpMessage, double *pValue)
1905 : {
1906 4 : return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
1907 : this,
1908 8 : GDALAlgorithmArgDecl(longName, chShortName, helpMessage, GAAT_REAL),
1909 8 : pValue));
1910 : }
1911 :
1912 : GDALInConstructionAlgorithmArg &
1913 1080 : GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
1914 : const std::string &helpMessage,
1915 : GDALArgDatasetValue *pValue, GDALArgDatasetValueType type)
1916 : {
1917 1080 : pValue->SetType(type);
1918 1080 : auto &arg = AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
1919 : this,
1920 2160 : GDALAlgorithmArgDecl(longName, chShortName, helpMessage, GAAT_DATASET),
1921 1080 : pValue));
1922 1080 : pValue->SetOwnerArgument(&arg);
1923 1080 : return arg;
1924 : }
1925 :
1926 : GDALInConstructionAlgorithmArg &
1927 3570 : GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
1928 : const std::string &helpMessage,
1929 : std::vector<std::string> *pValue)
1930 : {
1931 3570 : return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
1932 : this,
1933 7140 : GDALAlgorithmArgDecl(longName, chShortName, helpMessage,
1934 : GAAT_STRING_LIST),
1935 7140 : pValue));
1936 : }
1937 :
1938 : GDALInConstructionAlgorithmArg &
1939 49 : GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
1940 : const std::string &helpMessage, std::vector<int> *pValue)
1941 : {
1942 49 : return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
1943 : this,
1944 98 : GDALAlgorithmArgDecl(longName, chShortName, helpMessage,
1945 : GAAT_INTEGER_LIST),
1946 98 : pValue));
1947 : }
1948 :
1949 : GDALInConstructionAlgorithmArg &
1950 238 : GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
1951 : const std::string &helpMessage,
1952 : std::vector<double> *pValue)
1953 : {
1954 238 : return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
1955 : this,
1956 476 : GDALAlgorithmArgDecl(longName, chShortName, helpMessage,
1957 : GAAT_REAL_LIST),
1958 476 : pValue));
1959 : }
1960 :
1961 : GDALInConstructionAlgorithmArg &
1962 34 : GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
1963 : const std::string &helpMessage,
1964 : std::vector<GDALArgDatasetValue> *pValue,
1965 : GDALArgDatasetValueType)
1966 : {
1967 : // FIXME
1968 : // pValue->SetType(type);
1969 34 : return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
1970 : this,
1971 68 : GDALAlgorithmArgDecl(longName, chShortName, helpMessage,
1972 : GAAT_DATASET_LIST),
1973 68 : pValue));
1974 : }
1975 :
1976 : /************************************************************************/
1977 : /* GDALAlgorithm::AddInputDatasetArg() */
1978 : /************************************************************************/
1979 :
1980 : GDALInConstructionAlgorithmArg &
1981 521 : GDALAlgorithm::AddInputDatasetArg(GDALArgDatasetValue *pValue,
1982 : GDALArgDatasetValueType type,
1983 : bool positionalAndRequired)
1984 : {
1985 : auto &arg = AddArg(GDAL_ARG_NAME_INPUT, 'i',
1986 : CPLSPrintf("Input %s dataset",
1987 521 : GDALArgDatasetValueTypeName(type).c_str()),
1988 1042 : pValue, type);
1989 521 : if (positionalAndRequired)
1990 402 : arg.SetPositional().SetRequired();
1991 :
1992 : arg.SetAutoCompleteFunction(
1993 1173 : [type](const std::string ¤tValue)
1994 : {
1995 3 : std::vector<std::string> oRet;
1996 :
1997 3 : auto poDM = GetGDALDriverManager();
1998 6 : std::set<std::string> oExtensions;
1999 717 : for (int i = 0; i < poDM->GetDriverCount(); ++i)
2000 : {
2001 714 : auto poDriver = poDM->GetDriver(i);
2002 2142 : if (((type & GDAL_OF_RASTER) != 0 &&
2003 714 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER)) ||
2004 228 : ((type & GDAL_OF_VECTOR) != 0 &&
2005 1428 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR)) ||
2006 228 : ((type & GDAL_OF_MULTIDIM_RASTER) != 0 &&
2007 0 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER)))
2008 : {
2009 : const char *pszExtensions =
2010 486 : poDriver->GetMetadataItem(GDAL_DMD_EXTENSIONS);
2011 486 : if (pszExtensions)
2012 : {
2013 : const CPLStringList aosExts(
2014 636 : CSLTokenizeString2(pszExtensions, " ", 0));
2015 699 : for (const char *pszExt : cpl::Iterate(aosExts))
2016 381 : oExtensions.insert(CPLString(pszExt).tolower());
2017 : }
2018 : }
2019 : }
2020 :
2021 6 : std::string osDir = CPLGetDirnameSafe(currentValue.c_str());
2022 3 : auto psDir = VSIOpenDir(osDir.c_str(), 0, nullptr);
2023 6 : const std::string osSep = VSIGetDirectorySeparator(osDir.c_str());
2024 3 : if (currentValue.empty())
2025 1 : osDir.clear();
2026 : const std::string currentFilename =
2027 6 : CPLGetFilename(currentValue.c_str());
2028 3 : if (psDir)
2029 : {
2030 120 : while (const VSIDIREntry *psEntry = VSIGetNextDirEntry(psDir))
2031 : {
2032 117 : if ((currentFilename.empty() ||
2033 0 : STARTS_WITH(psEntry->pszName,
2034 117 : currentFilename.c_str())) &&
2035 117 : strcmp(psEntry->pszName, ".") != 0 &&
2036 351 : strcmp(psEntry->pszName, "..") != 0 &&
2037 117 : !strstr(psEntry->pszName, ".aux.xml"))
2038 : {
2039 348 : if (cpl::contains(
2040 : oExtensions,
2041 232 : CPLString(CPLGetExtensionSafe(psEntry->pszName))
2042 325 : .tolower()) ||
2043 93 : VSI_ISDIR(psEntry->nMode))
2044 : {
2045 54 : std::string osVal;
2046 27 : if (osDir.empty())
2047 4 : osVal = psEntry->pszName;
2048 : else
2049 46 : osVal = CPLFormFilenameSafe(
2050 46 : osDir.c_str(), psEntry->pszName, nullptr);
2051 27 : if (VSI_ISDIR(psEntry->nMode))
2052 4 : osVal += osSep;
2053 27 : oRet.push_back(osVal);
2054 : }
2055 : }
2056 117 : }
2057 3 : VSICloseDir(psDir);
2058 : }
2059 6 : return oRet;
2060 521 : });
2061 :
2062 521 : return arg;
2063 : }
2064 :
2065 : /************************************************************************/
2066 : /* GDALAlgorithm::AddInputDatasetArg() */
2067 : /************************************************************************/
2068 :
2069 : GDALInConstructionAlgorithmArg &
2070 1 : GDALAlgorithm::AddInputDatasetArg(std::vector<GDALArgDatasetValue> *pValue,
2071 : GDALArgDatasetValueType type,
2072 : bool positionalAndRequired)
2073 : {
2074 : auto &arg = AddArg(GDAL_ARG_NAME_INPUT, 'i',
2075 : CPLSPrintf("Input %s datasets",
2076 1 : GDALArgDatasetValueTypeName(type).c_str()),
2077 2 : pValue, type);
2078 1 : if (positionalAndRequired)
2079 1 : arg.SetPositional().SetRequired();
2080 1 : return arg;
2081 : }
2082 :
2083 : /************************************************************************/
2084 : /* GDALAlgorithm::AddOutputDatasetArg() */
2085 : /************************************************************************/
2086 :
2087 : GDALInConstructionAlgorithmArg &
2088 471 : GDALAlgorithm::AddOutputDatasetArg(GDALArgDatasetValue *pValue,
2089 : GDALArgDatasetValueType type,
2090 : bool positionalAndRequired)
2091 : {
2092 471 : pValue->SetInputFlags(GADV_NAME);
2093 471 : pValue->SetOutputFlags(GADV_OBJECT);
2094 : auto &arg = AddArg(GDAL_ARG_NAME_OUTPUT, 'o',
2095 : CPLSPrintf("Output %s dataset",
2096 471 : GDALArgDatasetValueTypeName(type).c_str()),
2097 1413 : pValue, type)
2098 471 : .SetIsInput(true)
2099 471 : .SetIsOutput(true);
2100 471 : if (positionalAndRequired)
2101 352 : arg.SetPositional().SetRequired();
2102 471 : return arg;
2103 : }
2104 :
2105 : /************************************************************************/
2106 : /* GDALAlgorithm::AddOverwriteArg() */
2107 : /************************************************************************/
2108 :
2109 462 : GDALInConstructionAlgorithmArg &GDALAlgorithm::AddOverwriteArg(bool *pValue)
2110 : {
2111 : return AddArg("overwrite", 0,
2112 924 : _("Whether overwriting existing output is allowed"), pValue)
2113 924 : .SetDefault(false);
2114 : }
2115 :
2116 : /************************************************************************/
2117 : /* GDALAlgorithm::AddUpdateArg() */
2118 : /************************************************************************/
2119 :
2120 243 : GDALInConstructionAlgorithmArg &GDALAlgorithm::AddUpdateArg(bool *pValue)
2121 : {
2122 : return AddArg(GDAL_ARG_NAME_UPDATE, 0,
2123 486 : _("Whether to open existing dataset in update mode"), pValue)
2124 486 : .SetDefault(false);
2125 : }
2126 :
2127 : /************************************************************************/
2128 : /* AddOptionsSuggestions() */
2129 : /************************************************************************/
2130 :
2131 19 : static bool AddOptionsSuggestions(const char *pszXML, int datasetType,
2132 : const std::string ¤tValue,
2133 : std::vector<std::string> &oRet)
2134 : {
2135 19 : if (!pszXML)
2136 0 : return false;
2137 38 : CPLXMLTreeCloser poTree(CPLParseXMLString(pszXML));
2138 19 : if (!poTree)
2139 0 : return false;
2140 : const CPLXMLNode *psRoot =
2141 19 : CPLGetXMLNode(poTree.get(), "=CreationOptionList");
2142 19 : if (!psRoot)
2143 4 : psRoot = CPLGetXMLNode(poTree.get(), "=LayerCreationOptionList");
2144 19 : if (!psRoot)
2145 2 : psRoot = CPLGetXMLNode(poTree.get(), "=OpenOptionList");
2146 19 : if (!psRoot)
2147 0 : return false;
2148 :
2149 309 : for (const CPLXMLNode *psChild = psRoot->psChild; psChild;
2150 290 : psChild = psChild->psNext)
2151 : {
2152 300 : const char *pszName = CPLGetXMLValue(psChild, "name", nullptr);
2153 310 : if (pszName && currentValue == pszName &&
2154 10 : EQUAL(psChild->pszValue, "Option"))
2155 : {
2156 10 : const char *pszType = CPLGetXMLValue(psChild, "type", "");
2157 10 : const char *pszMin = CPLGetXMLValue(psChild, "min", nullptr);
2158 10 : const char *pszMax = CPLGetXMLValue(psChild, "max", nullptr);
2159 10 : if (EQUAL(pszType, "string-select"))
2160 : {
2161 72 : for (const CPLXMLNode *psChild2 = psChild->psChild; psChild2;
2162 68 : psChild2 = psChild2->psNext)
2163 : {
2164 68 : if (EQUAL(psChild2->pszValue, "Value"))
2165 : {
2166 60 : oRet.push_back(CPLGetXMLValue(psChild2, "", ""));
2167 : }
2168 : }
2169 : }
2170 6 : else if (EQUAL(pszType, "boolean"))
2171 : {
2172 1 : oRet.push_back("NO");
2173 1 : oRet.push_back("YES");
2174 : }
2175 5 : else if (EQUAL(pszType, "int"))
2176 : {
2177 5 : if (pszMin && pszMax && atoi(pszMax) - atoi(pszMin) > 0 &&
2178 2 : atoi(pszMax) - atoi(pszMin) < 25)
2179 : {
2180 1 : const int nMax = atoi(pszMax);
2181 13 : for (int i = atoi(pszMin); i <= nMax; ++i)
2182 12 : oRet.push_back(std::to_string(i));
2183 : }
2184 : }
2185 :
2186 10 : if (oRet.empty())
2187 : {
2188 4 : if (pszMin && pszMax)
2189 : {
2190 1 : oRet.push_back(std::string("##"));
2191 2 : oRet.push_back(std::string("validity range: [")
2192 1 : .append(pszMin)
2193 1 : .append(",")
2194 1 : .append(pszMax)
2195 1 : .append("]"));
2196 : }
2197 3 : else if (pszMin)
2198 : {
2199 1 : oRet.push_back(std::string("##"));
2200 1 : oRet.push_back(
2201 1 : std::string("validity range: >= ").append(pszMin));
2202 : }
2203 2 : else if (pszMax)
2204 : {
2205 1 : oRet.push_back(std::string("##"));
2206 1 : oRet.push_back(
2207 1 : std::string("validity range: <= ").append(pszMax));
2208 : }
2209 1 : else if (const char *pszDescription =
2210 1 : CPLGetXMLValue(psChild, "description", nullptr))
2211 : {
2212 1 : oRet.push_back(std::string("##"));
2213 2 : oRet.push_back(std::string("type: ")
2214 1 : .append(pszType)
2215 1 : .append(", description: ")
2216 1 : .append(pszDescription));
2217 : }
2218 : }
2219 :
2220 10 : return true;
2221 : }
2222 : }
2223 :
2224 229 : for (const CPLXMLNode *psChild = psRoot->psChild; psChild;
2225 220 : psChild = psChild->psNext)
2226 : {
2227 220 : const char *pszName = CPLGetXMLValue(psChild, "name", nullptr);
2228 220 : if (pszName && EQUAL(psChild->pszValue, "Option"))
2229 : {
2230 220 : const char *pszScope = CPLGetXMLValue(psChild, "scope", nullptr);
2231 220 : if (!pszScope ||
2232 40 : (EQUAL(pszScope, "raster") &&
2233 40 : (datasetType & GDAL_OF_RASTER) != 0) ||
2234 20 : (EQUAL(pszScope, "vector") &&
2235 0 : (datasetType & GDAL_OF_VECTOR) != 0))
2236 : {
2237 200 : oRet.push_back(std::string(pszName).append("="));
2238 : }
2239 : }
2240 : }
2241 :
2242 9 : return false;
2243 : }
2244 :
2245 : /************************************************************************/
2246 : /* GDALAlgorithm::AddOpenOptionsArg() */
2247 : /************************************************************************/
2248 :
2249 : GDALInConstructionAlgorithmArg &
2250 499 : GDALAlgorithm::AddOpenOptionsArg(std::vector<std::string> *pValue)
2251 : {
2252 998 : auto &arg = AddArg(GDAL_ARG_NAME_OPEN_OPTION, 0, _("Open options"), pValue)
2253 998 : .AddAlias("oo")
2254 998 : .SetMetaVar("KEY=VALUE")
2255 499 : .SetCategory(GAAC_ADVANCED);
2256 :
2257 : arg.SetAutoCompleteFunction(
2258 6 : [this](const std::string ¤tValue)
2259 : {
2260 2 : std::vector<std::string> oRet;
2261 :
2262 2 : int datasetType =
2263 : GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_MULTIDIM_RASTER;
2264 2 : auto inputArg = GetArg(GDAL_ARG_NAME_INPUT);
2265 2 : if (inputArg && inputArg->GetType() == GAAT_DATASET)
2266 : {
2267 2 : auto &datasetValue = inputArg->Get<GDALArgDatasetValue>();
2268 2 : datasetType = datasetValue.GetType();
2269 : }
2270 :
2271 2 : auto inputFormat = GetArg(GDAL_ARG_NAME_INPUT_FORMAT);
2272 4 : if (inputFormat && inputFormat->GetType() == GAAT_STRING_LIST &&
2273 2 : inputFormat->IsExplicitlySet())
2274 : {
2275 : const auto &aosAllowedDrivers =
2276 1 : inputFormat->Get<std::vector<std::string>>();
2277 1 : if (aosAllowedDrivers.size() == 1)
2278 : {
2279 2 : auto poDriver = GetGDALDriverManager()->GetDriverByName(
2280 1 : aosAllowedDrivers[0].c_str());
2281 1 : if (poDriver)
2282 : {
2283 1 : AddOptionsSuggestions(
2284 1 : poDriver->GetMetadataItem(GDAL_DMD_OPENOPTIONLIST),
2285 : datasetType, currentValue, oRet);
2286 : }
2287 1 : return oRet;
2288 : }
2289 : }
2290 :
2291 1 : if (inputArg && inputArg->GetType() == GAAT_DATASET)
2292 : {
2293 1 : auto poDM = GetGDALDriverManager();
2294 1 : auto &datasetValue = inputArg->Get<GDALArgDatasetValue>();
2295 1 : const auto &osDSName = datasetValue.GetName();
2296 1 : const std::string osExt = CPLGetExtensionSafe(osDSName.c_str());
2297 1 : if (!osExt.empty())
2298 : {
2299 1 : std::set<std::string> oVisitedExtensions;
2300 239 : for (int i = 0; i < poDM->GetDriverCount(); ++i)
2301 : {
2302 238 : auto poDriver = poDM->GetDriver(i);
2303 714 : if (((datasetType & GDAL_OF_RASTER) != 0 &&
2304 238 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER)) ||
2305 76 : ((datasetType & GDAL_OF_VECTOR) != 0 &&
2306 476 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR)) ||
2307 76 : ((datasetType & GDAL_OF_MULTIDIM_RASTER) != 0 &&
2308 0 : poDriver->GetMetadataItem(
2309 0 : GDAL_DCAP_MULTIDIM_RASTER)))
2310 : {
2311 : const char *pszExtensions =
2312 162 : poDriver->GetMetadataItem(GDAL_DMD_EXTENSIONS);
2313 162 : if (pszExtensions)
2314 : {
2315 : const CPLStringList aosExts(
2316 106 : CSLTokenizeString2(pszExtensions, " ", 0));
2317 231 : for (const char *pszExt : cpl::Iterate(aosExts))
2318 : {
2319 129 : if (EQUAL(pszExt, osExt.c_str()) &&
2320 3 : !cpl::contains(oVisitedExtensions,
2321 : pszExt))
2322 : {
2323 1 : oVisitedExtensions.insert(pszExt);
2324 1 : if (AddOptionsSuggestions(
2325 : poDriver->GetMetadataItem(
2326 1 : GDAL_DMD_OPENOPTIONLIST),
2327 : datasetType, currentValue,
2328 : oRet))
2329 : {
2330 0 : return oRet;
2331 : }
2332 1 : break;
2333 : }
2334 : }
2335 : }
2336 : }
2337 : }
2338 : }
2339 : }
2340 :
2341 1 : return oRet;
2342 499 : });
2343 :
2344 499 : return arg;
2345 : }
2346 :
2347 : /************************************************************************/
2348 : /* ValidateFormat() */
2349 : /************************************************************************/
2350 :
2351 105 : bool GDALAlgorithm::ValidateFormat(const GDALAlgorithmArg &arg,
2352 : bool bStreamAllowed) const
2353 : {
2354 105 : if (arg.GetChoices().empty())
2355 : {
2356 : const auto Validate =
2357 161 : [this, &arg, bStreamAllowed](const std::string &val)
2358 : {
2359 82 : if (bStreamAllowed && val == "stream")
2360 8 : return true;
2361 :
2362 74 : auto hDriver = GDALGetDriverByName(val.c_str());
2363 74 : if (!hDriver)
2364 : {
2365 2 : ReportError(CE_Failure, CPLE_AppDefined,
2366 : "Invalid value for argument '%s'. Driver '%s' does "
2367 : "not exist",
2368 1 : arg.GetName().c_str(), val.c_str());
2369 1 : return false;
2370 : }
2371 :
2372 73 : const auto caps = arg.GetMetadataItem(GAAMDI_REQUIRED_CAPABILITIES);
2373 73 : if (caps)
2374 : {
2375 202 : for (const std::string &cap : *caps)
2376 : {
2377 135 : if (!GDALGetMetadataItem(hDriver, cap.c_str(), nullptr))
2378 : {
2379 8 : if (cap == GDAL_DCAP_CREATECOPY &&
2380 0 : std::find(caps->begin(), caps->end(),
2381 3 : GDAL_DCAP_RASTER) != caps->end() &&
2382 3 : GDALGetMetadataItem(hDriver, GDAL_DCAP_RASTER,
2383 8 : nullptr) &&
2384 3 : GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE,
2385 : nullptr))
2386 : {
2387 : // if it supports Create, it supports CreateCopy
2388 : }
2389 : else
2390 : {
2391 4 : ReportError(
2392 : CE_Failure, CPLE_AppDefined,
2393 : "Invalid value for argument '%s'. Driver '%s' "
2394 : "does "
2395 : "not expose the required '%s' capability.",
2396 2 : arg.GetName().c_str(), val.c_str(),
2397 : cap.c_str());
2398 2 : return false;
2399 : }
2400 : }
2401 : }
2402 : }
2403 71 : return true;
2404 82 : };
2405 :
2406 82 : if (arg.GetType() == GAAT_STRING)
2407 : {
2408 80 : return Validate(arg.Get<std::string>());
2409 : }
2410 4 : else if (arg.GetType() == GAAT_STRING_LIST)
2411 : {
2412 6 : for (const auto &val : arg.Get<std::vector<std::string>>())
2413 : {
2414 4 : if (!Validate(val))
2415 2 : return false;
2416 : }
2417 : }
2418 : }
2419 :
2420 25 : return true;
2421 : }
2422 :
2423 : /************************************************************************/
2424 : /* FormatAutoCompleteFunction() */
2425 : /************************************************************************/
2426 :
2427 : static std::vector<std::string>
2428 1 : FormatAutoCompleteFunction(const GDALAlgorithmArg &arg)
2429 : {
2430 1 : std::vector<std::string> res;
2431 1 : auto poDM = GetGDALDriverManager();
2432 239 : for (int i = 0; i < poDM->GetDriverCount(); ++i)
2433 : {
2434 238 : auto poDriver = poDM->GetDriver(i);
2435 :
2436 238 : const auto caps = arg.GetMetadataItem(GAAMDI_REQUIRED_CAPABILITIES);
2437 238 : if (caps)
2438 : {
2439 238 : bool ok = true;
2440 489 : for (const std::string &cap : *caps)
2441 : {
2442 400 : if (poDriver->GetMetadataItem(cap.c_str()))
2443 : {
2444 : }
2445 278 : else if (cap == GDAL_DCAP_CREATECOPY &&
2446 0 : std::find(caps->begin(), caps->end(),
2447 101 : GDAL_DCAP_RASTER) != caps->end() &&
2448 379 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) &&
2449 101 : poDriver->GetMetadataItem(GDAL_DCAP_CREATE))
2450 : {
2451 : // if it supports Create, it supports CreateCopy
2452 : }
2453 : else
2454 : {
2455 149 : ok = false;
2456 149 : break;
2457 : }
2458 : }
2459 238 : if (ok)
2460 : {
2461 89 : res.push_back(poDriver->GetDescription());
2462 : }
2463 : }
2464 : }
2465 1 : return res;
2466 : }
2467 :
2468 : /************************************************************************/
2469 : /* GDALAlgorithm::AddInputFormatsArg() */
2470 : /************************************************************************/
2471 :
2472 : GDALInConstructionAlgorithmArg &
2473 486 : GDALAlgorithm::AddInputFormatsArg(std::vector<std::string> *pValue)
2474 : {
2475 : auto &arg =
2476 972 : AddArg(GDAL_ARG_NAME_INPUT_FORMAT, 0, _("Input formats"), pValue)
2477 972 : .AddAlias("if")
2478 486 : .SetCategory(GAAC_ADVANCED);
2479 4 : arg.AddValidationAction([this, &arg]()
2480 490 : { return ValidateFormat(arg, false); });
2481 0 : arg.SetAutoCompleteFunction([&arg](const std::string &)
2482 486 : { return FormatAutoCompleteFunction(arg); });
2483 486 : return arg;
2484 : }
2485 :
2486 : /************************************************************************/
2487 : /* GDALAlgorithm::AddOutputFormatArg() */
2488 : /************************************************************************/
2489 :
2490 : GDALInConstructionAlgorithmArg &
2491 578 : GDALAlgorithm::AddOutputFormatArg(std::string *pValue, bool bStreamAllowed)
2492 : {
2493 : auto &arg = AddArg(GDAL_ARG_NAME_OUTPUT_FORMAT, 'f',
2494 : bStreamAllowed ? _("Output format (\"stream\" allowed)")
2495 : : _("Output format"),
2496 1156 : pValue)
2497 1156 : .AddAlias("of")
2498 578 : .AddAlias("format");
2499 101 : arg.AddValidationAction([this, &arg, bStreamAllowed]()
2500 679 : { return ValidateFormat(arg, bStreamAllowed); });
2501 1 : arg.SetAutoCompleteFunction([&arg](const std::string &)
2502 579 : { return FormatAutoCompleteFunction(arg); });
2503 578 : return arg;
2504 : }
2505 :
2506 : /************************************************************************/
2507 : /* GDALAlgorithm::AddOutputStringArg() */
2508 : /************************************************************************/
2509 :
2510 : GDALInConstructionAlgorithmArg &
2511 80 : GDALAlgorithm::AddOutputStringArg(std::string *pValue)
2512 : {
2513 : return AddArg("output-string", 0,
2514 160 : _("Output string, in which the result is placed"), pValue)
2515 80 : .SetHiddenForCLI()
2516 80 : .SetIsInput(false)
2517 160 : .SetIsOutput(true);
2518 : }
2519 :
2520 : /************************************************************************/
2521 : /* GDALAlgorithm::AddLayerNameArg() */
2522 : /************************************************************************/
2523 :
2524 : GDALInConstructionAlgorithmArg &
2525 1 : GDALAlgorithm::AddLayerNameArg(std::string *pValue)
2526 : {
2527 1 : return AddArg("layer", 'l', _("Layer name"), pValue);
2528 : }
2529 :
2530 : /************************************************************************/
2531 : /* GDALAlgorithm::AddLayerNameArg() */
2532 : /************************************************************************/
2533 :
2534 : GDALInConstructionAlgorithmArg &
2535 36 : GDALAlgorithm::AddLayerNameArg(std::vector<std::string> *pValue)
2536 : {
2537 36 : return AddArg("layer", 'l', _("Layer name"), pValue);
2538 : }
2539 :
2540 : /************************************************************************/
2541 : /* ValidateKeyValue() */
2542 : /************************************************************************/
2543 :
2544 17 : bool GDALAlgorithm::ValidateKeyValue(const GDALAlgorithmArg &arg) const
2545 : {
2546 24 : const auto Validate = [this, &arg](const std::string &val)
2547 : {
2548 22 : if (val.find('=') == std::string::npos)
2549 : {
2550 2 : ReportError(
2551 : CE_Failure, CPLE_AppDefined,
2552 : "Invalid value for argument '%s'. <KEY>=<VALUE> expected",
2553 2 : arg.GetName().c_str());
2554 2 : return false;
2555 : }
2556 :
2557 20 : return true;
2558 17 : };
2559 :
2560 17 : if (arg.GetType() == GAAT_STRING)
2561 : {
2562 0 : return Validate(arg.Get<std::string>());
2563 : }
2564 17 : else if (arg.GetType() == GAAT_STRING_LIST)
2565 : {
2566 37 : for (const auto &val : arg.Get<std::vector<std::string>>())
2567 : {
2568 22 : if (!Validate(val))
2569 2 : return false;
2570 : }
2571 : }
2572 :
2573 15 : return true;
2574 : }
2575 :
2576 : /************************************************************************/
2577 : /* GDALAlgorithm::AddCreationOptionsArg() */
2578 : /************************************************************************/
2579 :
2580 : GDALInConstructionAlgorithmArg &
2581 464 : GDALAlgorithm::AddCreationOptionsArg(std::vector<std::string> *pValue)
2582 : {
2583 928 : auto &arg = AddArg("creation-option", 0, _("Creation option"), pValue)
2584 928 : .AddAlias("co")
2585 464 : .SetMetaVar("<KEY>=<VALUE>");
2586 474 : arg.AddValidationAction([this, &arg]() { return ValidateKeyValue(arg); });
2587 :
2588 : arg.SetAutoCompleteFunction(
2589 45 : [this](const std::string ¤tValue)
2590 : {
2591 15 : std::vector<std::string> oRet;
2592 :
2593 15 : int datasetType =
2594 : GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_MULTIDIM_RASTER;
2595 15 : auto outputArg = GetArg(GDAL_ARG_NAME_OUTPUT);
2596 15 : if (outputArg && outputArg->GetType() == GAAT_DATASET)
2597 : {
2598 15 : auto &datasetValue = outputArg->Get<GDALArgDatasetValue>();
2599 15 : datasetType = datasetValue.GetType();
2600 : }
2601 :
2602 15 : auto outputFormat = GetArg(GDAL_ARG_NAME_OUTPUT_FORMAT);
2603 30 : if (outputFormat && outputFormat->GetType() == GAAT_STRING &&
2604 15 : outputFormat->IsExplicitlySet())
2605 : {
2606 12 : auto poDriver = GetGDALDriverManager()->GetDriverByName(
2607 6 : outputFormat->Get<std::string>().c_str());
2608 6 : if (poDriver)
2609 : {
2610 6 : AddOptionsSuggestions(
2611 6 : poDriver->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST),
2612 : datasetType, currentValue, oRet);
2613 : }
2614 6 : return oRet;
2615 : }
2616 :
2617 9 : if (outputArg && outputArg->GetType() == GAAT_DATASET)
2618 : {
2619 9 : auto poDM = GetGDALDriverManager();
2620 9 : auto &datasetValue = outputArg->Get<GDALArgDatasetValue>();
2621 9 : const auto &osDSName = datasetValue.GetName();
2622 9 : const std::string osExt = CPLGetExtensionSafe(osDSName.c_str());
2623 9 : if (!osExt.empty())
2624 : {
2625 9 : std::set<std::string> oVisitedExtensions;
2626 513 : for (int i = 0; i < poDM->GetDriverCount(); ++i)
2627 : {
2628 511 : auto poDriver = poDM->GetDriver(i);
2629 1533 : if (((datasetType & GDAL_OF_RASTER) != 0 &&
2630 511 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER)) ||
2631 152 : ((datasetType & GDAL_OF_VECTOR) != 0 &&
2632 1022 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR)) ||
2633 152 : ((datasetType & GDAL_OF_MULTIDIM_RASTER) != 0 &&
2634 0 : poDriver->GetMetadataItem(
2635 0 : GDAL_DCAP_MULTIDIM_RASTER)))
2636 : {
2637 : const char *pszExtensions =
2638 359 : poDriver->GetMetadataItem(GDAL_DMD_EXTENSIONS);
2639 359 : if (pszExtensions)
2640 : {
2641 : const CPLStringList aosExts(
2642 233 : CSLTokenizeString2(pszExtensions, " ", 0));
2643 511 : for (const char *pszExt : cpl::Iterate(aosExts))
2644 : {
2645 300 : if (EQUAL(pszExt, osExt.c_str()) &&
2646 13 : !cpl::contains(oVisitedExtensions,
2647 : pszExt))
2648 : {
2649 9 : oVisitedExtensions.insert(pszExt);
2650 9 : if (AddOptionsSuggestions(
2651 : poDriver->GetMetadataItem(
2652 9 : GDAL_DMD_CREATIONOPTIONLIST),
2653 : datasetType, currentValue,
2654 : oRet))
2655 : {
2656 7 : return oRet;
2657 : }
2658 2 : break;
2659 : }
2660 : }
2661 : }
2662 : }
2663 : }
2664 : }
2665 : }
2666 :
2667 2 : return oRet;
2668 464 : });
2669 :
2670 464 : return arg;
2671 : }
2672 :
2673 : /************************************************************************/
2674 : /* GDALAlgorithm::AddLayerCreationOptionsArg() */
2675 : /************************************************************************/
2676 :
2677 : GDALInConstructionAlgorithmArg &
2678 242 : GDALAlgorithm::AddLayerCreationOptionsArg(std::vector<std::string> *pValue)
2679 : {
2680 : auto &arg =
2681 484 : AddArg("layer-creation-option", 0, _("Layer creation option"), pValue)
2682 484 : .AddAlias("lco")
2683 242 : .SetMetaVar("<KEY>=<VALUE>");
2684 246 : arg.AddValidationAction([this, &arg]() { return ValidateKeyValue(arg); });
2685 :
2686 : arg.SetAutoCompleteFunction(
2687 5 : [this](const std::string ¤tValue)
2688 : {
2689 2 : std::vector<std::string> oRet;
2690 :
2691 2 : auto outputFormat = GetArg(GDAL_ARG_NAME_OUTPUT_FORMAT);
2692 4 : if (outputFormat && outputFormat->GetType() == GAAT_STRING &&
2693 2 : outputFormat->IsExplicitlySet())
2694 : {
2695 2 : auto poDriver = GetGDALDriverManager()->GetDriverByName(
2696 1 : outputFormat->Get<std::string>().c_str());
2697 1 : if (poDriver)
2698 : {
2699 1 : AddOptionsSuggestions(poDriver->GetMetadataItem(
2700 1 : GDAL_DS_LAYER_CREATIONOPTIONLIST),
2701 : GDAL_OF_VECTOR, currentValue, oRet);
2702 : }
2703 1 : return oRet;
2704 : }
2705 :
2706 1 : auto outputArg = GetArg(GDAL_ARG_NAME_OUTPUT);
2707 1 : if (outputArg && outputArg->GetType() == GAAT_DATASET)
2708 : {
2709 1 : auto poDM = GetGDALDriverManager();
2710 1 : auto &datasetValue = outputArg->Get<GDALArgDatasetValue>();
2711 1 : const auto &osDSName = datasetValue.GetName();
2712 1 : const std::string osExt = CPLGetExtensionSafe(osDSName.c_str());
2713 1 : if (!osExt.empty())
2714 : {
2715 1 : std::set<std::string> oVisitedExtensions;
2716 239 : for (int i = 0; i < poDM->GetDriverCount(); ++i)
2717 : {
2718 238 : auto poDriver = poDM->GetDriver(i);
2719 238 : if (poDriver->GetMetadataItem(GDAL_DCAP_VECTOR))
2720 : {
2721 : const char *pszExtensions =
2722 93 : poDriver->GetMetadataItem(GDAL_DMD_EXTENSIONS);
2723 93 : if (pszExtensions)
2724 : {
2725 : const CPLStringList aosExts(
2726 62 : CSLTokenizeString2(pszExtensions, " ", 0));
2727 157 : for (const char *pszExt : cpl::Iterate(aosExts))
2728 : {
2729 97 : if (EQUAL(pszExt, osExt.c_str()) &&
2730 1 : !cpl::contains(oVisitedExtensions,
2731 : pszExt))
2732 : {
2733 1 : oVisitedExtensions.insert(pszExt);
2734 1 : if (AddOptionsSuggestions(
2735 : poDriver->GetMetadataItem(
2736 1 : GDAL_DS_LAYER_CREATIONOPTIONLIST),
2737 : GDAL_OF_VECTOR, currentValue,
2738 : oRet))
2739 : {
2740 0 : return oRet;
2741 : }
2742 1 : break;
2743 : }
2744 : }
2745 : }
2746 : }
2747 : }
2748 : }
2749 : }
2750 :
2751 1 : return oRet;
2752 242 : });
2753 :
2754 242 : return arg;
2755 : }
2756 :
2757 : /************************************************************************/
2758 : /* GDALAlgorithm::AddBBOXArg() */
2759 : /************************************************************************/
2760 :
2761 : /** Add bbox=xmin,ymin,xmax,ymax argument. */
2762 : GDALInConstructionAlgorithmArg &
2763 149 : GDALAlgorithm::AddBBOXArg(std::vector<double> *pValue, const char *helpMessage)
2764 : {
2765 : auto &arg = AddArg("bbox", 0,
2766 : helpMessage ? helpMessage
2767 : : _("Bounding box as xmin,ymin,xmax,ymax"),
2768 298 : pValue)
2769 149 : .SetRepeatedArgAllowed(false)
2770 149 : .SetMinCount(4)
2771 149 : .SetMaxCount(4)
2772 149 : .SetDisplayHintAboutRepetition(false);
2773 : arg.AddValidationAction(
2774 25 : [&arg]()
2775 : {
2776 25 : const auto &val = arg.Get<std::vector<double>>();
2777 25 : CPLAssert(val.size() == 4);
2778 25 : if (!(val[0] <= val[2]) || !(val[1] <= val[3]))
2779 : {
2780 4 : CPLError(CE_Failure, CPLE_AppDefined,
2781 : "Value of 'bbox' should be xmin,ymin,xmax,ymax with "
2782 : "xmin <= xmax and ymin <= ymax");
2783 4 : return false;
2784 : }
2785 21 : return true;
2786 149 : });
2787 149 : return arg;
2788 : }
2789 :
2790 : /************************************************************************/
2791 : /* GDALAlgorithm::AddProgressArg() */
2792 : /************************************************************************/
2793 :
2794 347 : GDALInConstructionAlgorithmArg &GDALAlgorithm::AddProgressArg()
2795 : {
2796 : return AddArg("progress", 0, _("Display progress bar"),
2797 694 : &m_progressBarRequested)
2798 347 : .SetOnlyForCLI()
2799 694 : .SetCategory(GAAC_COMMON);
2800 : }
2801 :
2802 : /************************************************************************/
2803 : /* GDALAlgorithm::Run() */
2804 : /************************************************************************/
2805 :
2806 518 : bool GDALAlgorithm::Run(GDALProgressFunc pfnProgress, void *pProgressData)
2807 : {
2808 518 : if (m_selectedSubAlg)
2809 31 : return m_selectedSubAlg->Run(pfnProgress, pProgressData);
2810 :
2811 487 : if (m_helpRequested)
2812 : {
2813 1 : printf("%s", GetUsageForCLI(false).c_str()); /*ok*/
2814 1 : return true;
2815 : }
2816 :
2817 486 : if (m_JSONUsageRequested)
2818 : {
2819 3 : printf("%s", GetUsageAsJSON().c_str()); /*ok*/
2820 3 : return true;
2821 : }
2822 :
2823 483 : return ValidateArguments() && RunImpl(pfnProgress, pProgressData);
2824 : }
2825 :
2826 : /************************************************************************/
2827 : /* GDALAlgorithm::Finalize() */
2828 : /************************************************************************/
2829 :
2830 261 : bool GDALAlgorithm::Finalize()
2831 : {
2832 261 : bool ret = true;
2833 261 : if (m_selectedSubAlg)
2834 29 : ret = m_selectedSubAlg->Finalize();
2835 :
2836 3742 : for (auto &arg : m_args)
2837 : {
2838 3481 : if (arg->GetType() == GAAT_DATASET)
2839 : {
2840 316 : ret = arg->Get<GDALArgDatasetValue>().Close() && ret;
2841 : }
2842 3165 : else if (arg->GetType() == GAAT_DATASET_LIST)
2843 : {
2844 12 : for (auto &ds : arg->Get<std::vector<GDALArgDatasetValue>>())
2845 : {
2846 6 : ret = ds.Close() && ret;
2847 : }
2848 : }
2849 : }
2850 261 : return ret;
2851 : }
2852 :
2853 : /************************************************************************/
2854 : /* GDALAlgorithm::GetArgNamesForCLI() */
2855 : /************************************************************************/
2856 :
2857 : std::pair<std::vector<std::pair<GDALAlgorithmArg *, std::string>>, size_t>
2858 68 : GDALAlgorithm::GetArgNamesForCLI() const
2859 : {
2860 136 : std::vector<std::pair<GDALAlgorithmArg *, std::string>> options;
2861 :
2862 68 : size_t maxOptLen = 0;
2863 603 : for (const auto &arg : m_args)
2864 : {
2865 535 : if (arg->IsHiddenForCLI())
2866 25 : continue;
2867 510 : std::string opt;
2868 510 : bool addComma = false;
2869 510 : if (!arg->GetShortName().empty())
2870 : {
2871 121 : opt += '-';
2872 121 : opt += arg->GetShortName();
2873 121 : addComma = true;
2874 : }
2875 545 : for (const std::string &alias : arg->GetAliases())
2876 : {
2877 35 : if (addComma)
2878 15 : opt += ", ";
2879 35 : opt += "--";
2880 35 : opt += alias;
2881 35 : addComma = true;
2882 : }
2883 510 : if (!arg->GetName().empty())
2884 : {
2885 510 : if (addComma)
2886 141 : opt += ", ";
2887 510 : opt += "--";
2888 510 : opt += arg->GetName();
2889 : }
2890 510 : const auto &metaVar = arg->GetMetaVar();
2891 510 : if (!metaVar.empty())
2892 : {
2893 197 : opt += ' ';
2894 197 : if (metaVar.front() != '<')
2895 111 : opt += '<';
2896 197 : opt += metaVar;
2897 197 : if (metaVar.back() != '>')
2898 111 : opt += '>';
2899 : }
2900 510 : maxOptLen = std::max(maxOptLen, opt.size());
2901 510 : options.emplace_back(arg.get(), opt);
2902 : }
2903 :
2904 136 : return std::make_pair(std::move(options), maxOptLen);
2905 : }
2906 :
2907 : /************************************************************************/
2908 : /* GDALAlgorithm::GetUsageForCLI() */
2909 : /************************************************************************/
2910 :
2911 : std::string
2912 66 : GDALAlgorithm::GetUsageForCLI(bool shortUsage,
2913 : const UsageOptions &usageOptions) const
2914 : {
2915 66 : if (m_selectedSubAlg)
2916 4 : return m_selectedSubAlg->GetUsageForCLI(shortUsage, usageOptions);
2917 :
2918 124 : std::string osRet(usageOptions.isPipelineStep ? "*" : "Usage:");
2919 124 : std::string osPath;
2920 89 : for (const std::string &s : m_callPath)
2921 : {
2922 27 : if (!osPath.empty())
2923 3 : osPath += ' ';
2924 27 : osPath += s;
2925 : }
2926 62 : osRet += ' ';
2927 62 : osRet += osPath;
2928 :
2929 62 : bool hasNonPositionals = false;
2930 561 : for (const auto &arg : m_args)
2931 : {
2932 499 : if (!arg->IsHiddenForCLI() && !arg->IsPositional())
2933 421 : hasNonPositionals = true;
2934 : }
2935 :
2936 62 : if (HasSubAlgorithms())
2937 : {
2938 4 : if (m_callPath.size() == 1)
2939 : {
2940 3 : osRet += " <COMMAND>";
2941 3 : if (hasNonPositionals)
2942 3 : osRet += " [OPTIONS]";
2943 3 : osRet += "\nwhere <COMMAND> is one of:\n";
2944 : }
2945 : else
2946 : {
2947 1 : osRet += " <SUBCOMMAND>";
2948 1 : if (hasNonPositionals)
2949 1 : osRet += " [OPTIONS]";
2950 1 : osRet += "\nwhere <SUBCOMMAND> is one of:\n";
2951 : }
2952 4 : size_t maxNameLen = 0;
2953 20 : for (const auto &subAlgName : GetSubAlgorithmNames())
2954 : {
2955 16 : maxNameLen = std::max(maxNameLen, subAlgName.size());
2956 : }
2957 20 : for (const auto &subAlgName : GetSubAlgorithmNames())
2958 : {
2959 32 : auto subAlg = InstantiateSubAlgorithm(subAlgName);
2960 16 : assert(subAlg);
2961 16 : const std::string &name(subAlg->GetName());
2962 16 : osRet += " - ";
2963 16 : osRet += name;
2964 16 : osRet += ": ";
2965 16 : osRet.append(maxNameLen - name.size(), ' ');
2966 16 : osRet += subAlg->GetDescription();
2967 16 : if (!subAlg->m_aliases.empty())
2968 : {
2969 0 : bool first = true;
2970 0 : for (const auto &alias : subAlg->GetAliases())
2971 : {
2972 0 : if (alias == GDALAlgorithmRegistry::HIDDEN_ALIAS_SEPARATOR)
2973 0 : break;
2974 0 : if (first)
2975 0 : osRet += " (alias: ";
2976 : else
2977 0 : osRet += ", ";
2978 0 : osRet += alias;
2979 0 : first = false;
2980 : }
2981 0 : if (!first)
2982 : {
2983 0 : osRet += ')';
2984 : }
2985 : }
2986 16 : osRet += '\n';
2987 : }
2988 :
2989 4 : if (shortUsage && hasNonPositionals)
2990 : {
2991 2 : osRet += "\nTry '";
2992 2 : osRet += osPath;
2993 2 : osRet += " --help' for help.\n";
2994 : }
2995 : }
2996 : else
2997 : {
2998 58 : if (!m_args.empty())
2999 : {
3000 58 : if (hasNonPositionals)
3001 58 : osRet += " [OPTIONS]";
3002 91 : for (const auto *arg : m_positionalArgs)
3003 : {
3004 33 : const std::string &metavar = arg->GetMetaVar();
3005 33 : if (!metavar.empty() && metavar[0] == '<')
3006 : {
3007 1 : osRet += metavar;
3008 : }
3009 : else
3010 : {
3011 32 : osRet += " <";
3012 32 : osRet += metavar;
3013 32 : osRet += '>';
3014 : }
3015 : }
3016 : }
3017 :
3018 58 : const size_t nLenFirstLine = osRet.size();
3019 58 : osRet += '\n';
3020 58 : if (usageOptions.isPipelineStep)
3021 : {
3022 12 : osRet.append(nLenFirstLine, '-');
3023 12 : osRet += '\n';
3024 : }
3025 :
3026 58 : if (shortUsage)
3027 : {
3028 4 : osRet += "Try '";
3029 4 : osRet += osPath;
3030 4 : osRet += " --help' for help.\n";
3031 4 : return osRet;
3032 : }
3033 :
3034 54 : osRet += '\n';
3035 54 : osRet += m_description;
3036 54 : osRet += '\n';
3037 : }
3038 :
3039 58 : if (!m_args.empty() && !shortUsage)
3040 : {
3041 112 : std::vector<std::pair<GDALAlgorithmArg *, std::string>> options;
3042 : size_t maxOptLen;
3043 56 : std::tie(options, maxOptLen) = GetArgNamesForCLI();
3044 56 : if (usageOptions.maxOptLen)
3045 12 : maxOptLen = usageOptions.maxOptLen;
3046 :
3047 : const auto OutputArg =
3048 339 : [this, maxOptLen, &osRet](const GDALAlgorithmArg *arg,
3049 2293 : const std::string &opt)
3050 : {
3051 339 : osRet += " ";
3052 339 : osRet += opt;
3053 339 : osRet += " ";
3054 339 : osRet.append(maxOptLen - opt.size(), ' ');
3055 339 : osRet += arg->GetDescription();
3056 :
3057 339 : const auto &choices = arg->GetChoices();
3058 339 : if (!choices.empty())
3059 : {
3060 5 : osRet += ". ";
3061 5 : osRet += arg->GetMetaVar();
3062 5 : osRet += '=';
3063 5 : bool firstChoice = true;
3064 27 : for (const auto &choice : choices)
3065 : {
3066 22 : if (!firstChoice)
3067 17 : osRet += '|';
3068 22 : osRet += choice;
3069 22 : firstChoice = false;
3070 : }
3071 : }
3072 :
3073 339 : if (arg->GetType() == GAAT_DATASET)
3074 : {
3075 9 : auto &val = arg->Get<GDALArgDatasetValue>();
3076 10 : if (val.GetInputFlags() == GADV_NAME &&
3077 1 : val.GetOutputFlags() == GADV_OBJECT)
3078 : {
3079 1 : osRet += " (created by algorithm)";
3080 : }
3081 : }
3082 :
3083 339 : if (arg->GetType() == GAAT_STRING && arg->HasDefaultValue())
3084 : {
3085 3 : osRet += " (default: ";
3086 3 : osRet += arg->GetDefault<std::string>();
3087 3 : osRet += ')';
3088 : }
3089 336 : else if (arg->GetType() == GAAT_BOOLEAN && arg->HasDefaultValue())
3090 : {
3091 5 : if (arg->GetDefault<bool>())
3092 0 : osRet += " (default: true)";
3093 : }
3094 331 : else if (arg->GetType() == GAAT_INTEGER && arg->HasDefaultValue())
3095 : {
3096 1 : osRet += " (default: ";
3097 1 : osRet += CPLSPrintf("%d", arg->GetDefault<int>());
3098 1 : osRet += ')';
3099 : }
3100 330 : else if (arg->GetType() == GAAT_REAL && arg->HasDefaultValue())
3101 : {
3102 1 : osRet += " (default: ";
3103 1 : osRet += CPLSPrintf("%g", arg->GetDefault<double>());
3104 1 : osRet += ')';
3105 : }
3106 :
3107 339 : if (arg->GetDisplayHintAboutRepetition())
3108 : {
3109 338 : if (arg->GetMinCount() > 0 &&
3110 6 : arg->GetMinCount() == arg->GetMaxCount())
3111 : {
3112 2 : osRet += CPLSPrintf(" [%d values]", arg->GetMaxCount());
3113 : }
3114 334 : else if (arg->GetMinCount() > 0 &&
3115 4 : arg->GetMaxCount() < GDALAlgorithmArgDecl::UNBOUNDED)
3116 : {
3117 : osRet += CPLSPrintf(" [%d..%d values]", arg->GetMinCount(),
3118 4 : arg->GetMaxCount());
3119 : }
3120 326 : else if (arg->GetMinCount() > 0)
3121 : {
3122 0 : osRet += CPLSPrintf(" [%d.. values]", arg->GetMinCount());
3123 : }
3124 326 : else if (arg->GetMaxCount() > 1)
3125 : {
3126 69 : osRet += " [may be repeated]";
3127 : }
3128 : }
3129 :
3130 339 : if (arg->IsRequired())
3131 : {
3132 16 : osRet += " [required]";
3133 : }
3134 :
3135 339 : osRet += '\n';
3136 :
3137 339 : const auto &mutualExclusionGroup = arg->GetMutualExclusionGroup();
3138 339 : if (!mutualExclusionGroup.empty())
3139 : {
3140 28 : std::string otherArgs;
3141 185 : for (const auto &otherArg : m_args)
3142 : {
3143 171 : if (otherArg->IsHiddenForCLI() || otherArg.get() == arg)
3144 18 : continue;
3145 153 : if (otherArg->GetMutualExclusionGroup() ==
3146 : mutualExclusionGroup)
3147 : {
3148 20 : if (!otherArgs.empty())
3149 6 : otherArgs += ", ";
3150 20 : otherArgs += "--";
3151 20 : otherArgs += otherArg->GetName();
3152 : }
3153 : }
3154 14 : if (!otherArgs.empty())
3155 : {
3156 14 : osRet += " ";
3157 14 : osRet += " ";
3158 14 : osRet.append(maxOptLen, ' ');
3159 14 : osRet += "Mutually exclusive with ";
3160 14 : osRet += otherArgs;
3161 14 : osRet += '\n';
3162 : }
3163 : }
3164 339 : };
3165 :
3166 56 : if (!m_positionalArgs.empty())
3167 : {
3168 21 : osRet += "\nPositional arguments:\n";
3169 194 : for (const auto &[arg, opt] : options)
3170 : {
3171 173 : if (arg->IsPositional())
3172 28 : OutputArg(arg, opt);
3173 : }
3174 : }
3175 :
3176 56 : if (hasNonPositionals)
3177 : {
3178 56 : bool hasCommon = false;
3179 56 : bool hasBase = false;
3180 56 : bool hasAdvanced = false;
3181 56 : bool hasEsoteric = false;
3182 112 : std::vector<std::string> categories;
3183 455 : for (const auto &iter : options)
3184 : {
3185 399 : const auto &arg = iter.first;
3186 399 : if (!arg->IsPositional())
3187 : {
3188 371 : const auto &category = arg->GetCategory();
3189 371 : if (category == GAAC_COMMON)
3190 : {
3191 286 : hasCommon = true;
3192 : }
3193 85 : else if (category == GAAC_BASE)
3194 : {
3195 67 : hasBase = true;
3196 : }
3197 18 : else if (category == GAAC_ADVANCED)
3198 : {
3199 14 : hasAdvanced = true;
3200 : }
3201 4 : else if (category == GAAC_ESOTERIC)
3202 : {
3203 3 : hasEsoteric = true;
3204 : }
3205 1 : else if (std::find(categories.begin(), categories.end(),
3206 1 : category) == categories.end())
3207 : {
3208 1 : categories.push_back(category);
3209 : }
3210 : }
3211 : }
3212 56 : if (hasAdvanced)
3213 4 : categories.insert(categories.begin(), GAAC_ADVANCED);
3214 56 : if (hasBase)
3215 31 : categories.insert(categories.begin(), GAAC_BASE);
3216 56 : if (hasCommon && !usageOptions.isPipelineStep)
3217 44 : categories.insert(categories.begin(), GAAC_COMMON);
3218 56 : if (hasEsoteric)
3219 1 : categories.push_back(GAAC_ESOTERIC);
3220 :
3221 137 : for (const auto &category : categories)
3222 : {
3223 81 : osRet += "\n";
3224 81 : if (category != GAAC_BASE)
3225 : {
3226 50 : osRet += category;
3227 50 : osRet += ' ';
3228 : }
3229 81 : osRet += "Options:\n";
3230 687 : for (const auto &[arg, opt] : options)
3231 : {
3232 606 : if (!arg->IsPositional() && arg->GetCategory() == category)
3233 311 : OutputArg(arg, opt);
3234 : }
3235 : }
3236 : }
3237 : }
3238 :
3239 58 : if (!m_longDescription.empty())
3240 : {
3241 5 : osRet += '\n';
3242 5 : osRet += m_longDescription;
3243 5 : osRet += '\n';
3244 : }
3245 :
3246 58 : if (!m_helpURL.empty())
3247 : {
3248 58 : osRet += "\nFor more details, consult ";
3249 58 : osRet += GetHelpFullURL();
3250 58 : osRet += '\n';
3251 : }
3252 :
3253 58 : if (!m_callPath.empty() && m_callPath[0] == "gdal")
3254 : {
3255 : osRet += "\nWARNING: the gdal command is provisionally provided as an "
3256 : "alternative interface to GDAL and OGR command line "
3257 : "utilities.\nThe project reserves the right to modify, "
3258 : "rename, reorganize, and change the behavior of the utility\n"
3259 : "until it is officially frozen in a future feature release of "
3260 0 : "GDAL.\n";
3261 : }
3262 :
3263 58 : return osRet;
3264 : }
3265 :
3266 : /************************************************************************/
3267 : /* GDALAlgorithm::GetUsageAsJSON() */
3268 : /************************************************************************/
3269 :
3270 88 : std::string GDALAlgorithm::GetUsageAsJSON() const
3271 : {
3272 176 : CPLJSONDocument oDoc;
3273 176 : auto oRoot = oDoc.GetRoot();
3274 :
3275 88 : if (m_displayInJSONUsage)
3276 : {
3277 86 : oRoot.Add("name", m_name);
3278 86 : CPLJSONArray jFullPath;
3279 175 : for (const std::string &s : m_callPath)
3280 : {
3281 89 : jFullPath.Add(s);
3282 : }
3283 86 : oRoot.Add("full_path", jFullPath);
3284 : }
3285 :
3286 88 : oRoot.Add("description", m_description);
3287 88 : if (!m_helpURL.empty())
3288 : {
3289 88 : oRoot.Add("short_url", m_helpURL);
3290 88 : oRoot.Add("url", GetHelpFullURL());
3291 : }
3292 :
3293 176 : CPLJSONArray jSubAlgorithms;
3294 125 : for (const auto &subAlgName : GetSubAlgorithmNames())
3295 : {
3296 74 : auto subAlg = InstantiateSubAlgorithm(subAlgName);
3297 37 : assert(subAlg);
3298 37 : if (subAlg->m_displayInJSONUsage)
3299 : {
3300 34 : CPLJSONDocument oSubDoc;
3301 34 : CPL_IGNORE_RET_VAL(oSubDoc.LoadMemory(subAlg->GetUsageAsJSON()));
3302 34 : jSubAlgorithms.Add(oSubDoc.GetRoot());
3303 : }
3304 : }
3305 88 : oRoot.Add("sub_algorithms", jSubAlgorithms);
3306 :
3307 570 : const auto ProcessArg = [](const GDALAlgorithmArg *arg)
3308 : {
3309 570 : CPLJSONObject jArg;
3310 570 : jArg.Add("name", arg->GetName());
3311 570 : jArg.Add("type", GDALAlgorithmArgTypeName(arg->GetType()));
3312 570 : jArg.Add("description", arg->GetDescription());
3313 570 : const auto &choices = arg->GetChoices();
3314 570 : if (!choices.empty())
3315 : {
3316 11 : CPLJSONArray jChoices;
3317 121 : for (const auto &choice : choices)
3318 110 : jChoices.Add(choice);
3319 11 : jArg.Add("choices", jChoices);
3320 : }
3321 570 : if (arg->HasDefaultValue())
3322 : {
3323 83 : switch (arg->GetType())
3324 : {
3325 73 : case GAAT_BOOLEAN:
3326 73 : jArg.Add("default", arg->GetDefault<bool>());
3327 73 : break;
3328 8 : case GAAT_STRING:
3329 8 : jArg.Add("default", arg->GetDefault<std::string>());
3330 8 : break;
3331 1 : case GAAT_INTEGER:
3332 1 : jArg.Add("default", arg->GetDefault<int>());
3333 1 : break;
3334 1 : case GAAT_REAL:
3335 1 : jArg.Add("default", arg->GetDefault<double>());
3336 1 : break;
3337 0 : case GAAT_DATASET:
3338 : case GAAT_STRING_LIST:
3339 : case GAAT_INTEGER_LIST:
3340 : case GAAT_REAL_LIST:
3341 : case GAAT_DATASET_LIST:
3342 0 : CPLError(CE_Warning, CPLE_AppDefined,
3343 : "Unhandled default value for arg %s",
3344 0 : arg->GetName().c_str());
3345 0 : break;
3346 : }
3347 : }
3348 570 : jArg.Add("required", arg->IsRequired());
3349 570 : if (GDALAlgorithmArgTypeIsList(arg->GetType()))
3350 : {
3351 206 : jArg.Add("packed_values_allowed", arg->GetPackedValuesAllowed());
3352 206 : jArg.Add("repeated_arg_allowed", arg->GetRepeatedArgAllowed());
3353 206 : jArg.Add("min_count", arg->GetMinCount());
3354 206 : jArg.Add("max_count", arg->GetMaxCount());
3355 : }
3356 570 : jArg.Add("category", arg->GetCategory());
3357 :
3358 570 : if (arg->GetType() == GAAT_DATASET)
3359 : {
3360 81 : const auto &val = arg->Get<GDALArgDatasetValue>();
3361 : {
3362 81 : CPLJSONArray jAr;
3363 81 : if (val.GetType() & GDAL_OF_RASTER)
3364 56 : jAr.Add("raster");
3365 81 : if (val.GetType() & GDAL_OF_VECTOR)
3366 31 : jAr.Add("vector");
3367 81 : if (val.GetType() & GDAL_OF_MULTIDIM_RASTER)
3368 2 : jAr.Add("muldim_raster");
3369 81 : jArg.Add("dataset_type", jAr);
3370 : }
3371 :
3372 114 : const auto GetFlags = [](int flags)
3373 : {
3374 114 : CPLJSONArray jAr;
3375 114 : if (flags & GADV_NAME)
3376 81 : jAr.Add("name");
3377 114 : if (flags & GADV_OBJECT)
3378 105 : jAr.Add("dataset");
3379 114 : return jAr;
3380 : };
3381 :
3382 81 : if (arg->IsInput())
3383 : {
3384 81 : jArg.Add("input_flags", GetFlags(val.GetInputFlags()));
3385 : }
3386 81 : if (arg->IsOutput())
3387 : {
3388 33 : jArg.Add("output_flags", GetFlags(val.GetOutputFlags()));
3389 : }
3390 : }
3391 :
3392 570 : const auto &mutualExclusionGroup = arg->GetMutualExclusionGroup();
3393 570 : if (!mutualExclusionGroup.empty())
3394 : {
3395 52 : jArg.Add("mutual_exclusion_group", mutualExclusionGroup);
3396 : }
3397 :
3398 1140 : const auto &metadata = arg->GetMetadata();
3399 570 : if (!metadata.empty())
3400 : {
3401 57 : CPLJSONObject jMetadata;
3402 114 : for (const auto &[key, values] : metadata)
3403 : {
3404 114 : CPLJSONArray jValue;
3405 141 : for (const auto &value : values)
3406 84 : jValue.Add(value);
3407 57 : jMetadata.Add(key, jValue);
3408 : }
3409 57 : jArg.Add("metadata", jMetadata);
3410 : }
3411 :
3412 1140 : return jArg;
3413 : };
3414 :
3415 : {
3416 88 : CPLJSONArray jArgs;
3417 1128 : for (const auto &arg : m_args)
3418 : {
3419 1040 : if (!arg->IsOnlyForCLI() && arg->IsInput() && !arg->IsOutput())
3420 534 : jArgs.Add(ProcessArg(arg.get()));
3421 : }
3422 88 : oRoot.Add("input_arguments", jArgs);
3423 : }
3424 :
3425 : {
3426 88 : CPLJSONArray jArgs;
3427 1128 : for (const auto &arg : m_args)
3428 : {
3429 1040 : if (!arg->IsOnlyForCLI() && !arg->IsInput() && arg->IsOutput())
3430 3 : jArgs.Add(ProcessArg(arg.get()));
3431 : }
3432 88 : oRoot.Add("output_arguments", jArgs);
3433 : }
3434 :
3435 : {
3436 88 : CPLJSONArray jArgs;
3437 1128 : for (const auto &arg : m_args)
3438 : {
3439 1040 : if (!arg->IsOnlyForCLI() && arg->IsInput() && arg->IsOutput())
3440 33 : jArgs.Add(ProcessArg(arg.get()));
3441 : }
3442 88 : oRoot.Add("input_output_arguments", jArgs);
3443 : }
3444 :
3445 176 : return oDoc.SaveAsString();
3446 : }
3447 :
3448 : /************************************************************************/
3449 : /* GDALAlgorithm::GetAutoComplete() */
3450 : /************************************************************************/
3451 :
3452 : std::vector<std::string>
3453 43 : GDALAlgorithm::GetAutoComplete(std::vector<std::string> &args,
3454 : bool showAllOptions)
3455 : {
3456 43 : std::vector<std::string> ret;
3457 :
3458 86 : std::string option;
3459 86 : std::string value;
3460 43 : ExtractLastOptionAndValue(args, option, value);
3461 :
3462 51 : if (option.empty() && !args.empty() && !args.back().empty() &&
3463 8 : args.back()[0] == '-')
3464 : {
3465 : // List available options
3466 88 : for (const auto &arg : GetArgs())
3467 : {
3468 160 : if (arg->IsHiddenForCLI() ||
3469 153 : (!showAllOptions &&
3470 204 : (arg->GetName() == "help" || arg->GetName() == "drivers" ||
3471 168 : arg->GetName() == "config" || arg->GetName() == "version" ||
3472 50 : arg->GetName() == "json-usage")))
3473 : {
3474 32 : continue;
3475 : }
3476 49 : if (!arg->GetShortName().empty())
3477 : {
3478 14 : ret.push_back(std::string("-").append(arg->GetShortName()));
3479 : }
3480 66 : for (const std::string &alias : arg->GetAliases())
3481 : {
3482 17 : ret.push_back(std::string("--").append(alias));
3483 : }
3484 49 : if (!arg->GetName().empty())
3485 : {
3486 49 : ret.push_back(std::string("--").append(arg->GetName()));
3487 : }
3488 : }
3489 : }
3490 36 : else if (!option.empty())
3491 : {
3492 : // List possible choices for current option
3493 33 : auto arg = GetArg(option);
3494 33 : if (arg && arg->GetType() != GAAT_BOOLEAN)
3495 : {
3496 33 : ret = arg->GetChoices();
3497 33 : if (ret.empty())
3498 : {
3499 : {
3500 29 : CPLErrorStateBackuper oErrorQuieter(CPLQuietErrorHandler);
3501 29 : SetParseForAutoCompletion();
3502 29 : CPL_IGNORE_RET_VAL(ParseCommandLineArguments(args));
3503 : }
3504 29 : ret = arg->GetAutoCompleteChoices(value);
3505 : }
3506 33 : if (ret.empty())
3507 : {
3508 1 : ret.push_back("**");
3509 1 : ret.push_back(
3510 1 : std::string("description: ").append(arg->GetDescription()));
3511 : }
3512 : }
3513 : }
3514 3 : else if (!args.empty() && STARTS_WITH(args.back().c_str(), "/vsi"))
3515 : {
3516 1 : auto arg = GetArg(GDAL_ARG_NAME_INPUT);
3517 1 : if (arg)
3518 : {
3519 1 : ret = arg->GetAutoCompleteChoices(args.back());
3520 : }
3521 : }
3522 : else
3523 : {
3524 : // List possible sub-algorithms
3525 2 : ret = GetSubAlgorithmNames();
3526 : }
3527 :
3528 86 : return ret;
3529 : }
3530 :
3531 : /************************************************************************/
3532 : /* GDALAlgorithm::ExtractLastOptionAndValue() */
3533 : /************************************************************************/
3534 :
3535 43 : void GDALAlgorithm::ExtractLastOptionAndValue(std::vector<std::string> &args,
3536 : std::string &option,
3537 : std::string &value) const
3538 : {
3539 43 : if (!args.empty() && !args.back().empty() && args.back()[0] == '-')
3540 : {
3541 28 : const auto nPosEqual = args.back().find('=');
3542 28 : if (nPosEqual == std::string::npos)
3543 : {
3544 : // Deal with "gdal ... --option"
3545 17 : if (GetArg(args.back()))
3546 : {
3547 10 : option = args.back();
3548 10 : args.pop_back();
3549 : }
3550 : }
3551 : else
3552 : {
3553 : // Deal with "gdal ... --option=<value>"
3554 11 : if (GetArg(args.back().substr(0, nPosEqual)))
3555 : {
3556 11 : option = args.back().substr(0, nPosEqual);
3557 11 : value = args.back().substr(nPosEqual + 1);
3558 11 : args.pop_back();
3559 : }
3560 : }
3561 : }
3562 27 : else if (args.size() >= 2 && !args[args.size() - 2].empty() &&
3563 12 : args[args.size() - 2][0] == '-')
3564 : {
3565 : // Deal with "gdal ... --option <value>"
3566 12 : auto arg = GetArg(args[args.size() - 2]);
3567 12 : if (arg && arg->GetType() != GAAT_BOOLEAN)
3568 : {
3569 12 : option = args[args.size() - 2];
3570 12 : value = args.back();
3571 12 : args.pop_back();
3572 : }
3573 : }
3574 :
3575 43 : const auto IsKeyValueOption = [](const std::string &osStr)
3576 : {
3577 100 : return osStr == "--co" || osStr == "--creation-option" ||
3578 81 : osStr == "--lco" || osStr == "--layer-creation-option" ||
3579 98 : osStr == "--oo" || osStr == "--open-option";
3580 : };
3581 :
3582 43 : if (IsKeyValueOption(option))
3583 : {
3584 19 : const auto nPosEqual = value.find('=');
3585 19 : if (nPosEqual != std::string::npos)
3586 : {
3587 10 : value.resize(nPosEqual);
3588 : }
3589 : }
3590 43 : }
3591 :
3592 : /************************************************************************/
3593 : /* GDALAlgorithmRelease() */
3594 : /************************************************************************/
3595 :
3596 : /** Release a handle to an algorithm.
3597 : *
3598 : * @since 3.11
3599 : */
3600 602 : void GDALAlgorithmRelease(GDALAlgorithmH hAlg)
3601 : {
3602 602 : delete hAlg;
3603 602 : }
3604 :
3605 : /************************************************************************/
3606 : /* GDALAlgorithmGetName() */
3607 : /************************************************************************/
3608 :
3609 : /** Return the algorithm name.
3610 : *
3611 : * @param hAlg Handle to an algorithm. Must NOT be null.
3612 : * @return algorithm name whose lifetime is bound to hAlg and which must not
3613 : * be freed.
3614 : * @since 3.11
3615 : */
3616 2 : const char *GDALAlgorithmGetName(GDALAlgorithmH hAlg)
3617 : {
3618 2 : VALIDATE_POINTER1(hAlg, __func__, nullptr);
3619 2 : return hAlg->ptr->GetName().c_str();
3620 : }
3621 :
3622 : /************************************************************************/
3623 : /* GDALAlgorithmGetDescription() */
3624 : /************************************************************************/
3625 :
3626 : /** Return the algorithm (short) description.
3627 : *
3628 : * @param hAlg Handle to an algorithm. Must NOT be null.
3629 : * @return algorithm description whose lifetime is bound to hAlg and which must
3630 : * not be freed.
3631 : * @since 3.11
3632 : */
3633 2 : const char *GDALAlgorithmGetDescription(GDALAlgorithmH hAlg)
3634 : {
3635 2 : VALIDATE_POINTER1(hAlg, __func__, nullptr);
3636 2 : return hAlg->ptr->GetDescription().c_str();
3637 : }
3638 :
3639 : /************************************************************************/
3640 : /* GDALAlgorithmGetLongDescription() */
3641 : /************************************************************************/
3642 :
3643 : /** Return the algorithm (longer) description.
3644 : *
3645 : * @param hAlg Handle to an algorithm. Must NOT be null.
3646 : * @return algorithm description whose lifetime is bound to hAlg and which must
3647 : * not be freed.
3648 : * @since 3.11
3649 : */
3650 2 : const char *GDALAlgorithmGetLongDescription(GDALAlgorithmH hAlg)
3651 : {
3652 2 : VALIDATE_POINTER1(hAlg, __func__, nullptr);
3653 2 : return hAlg->ptr->GetLongDescription().c_str();
3654 : }
3655 :
3656 : /************************************************************************/
3657 : /* GDALAlgorithmGetHelpFullURL() */
3658 : /************************************************************************/
3659 :
3660 : /** Return the algorithm full URL.
3661 : *
3662 : * @param hAlg Handle to an algorithm. Must NOT be null.
3663 : * @return algorithm URL whose lifetime is bound to hAlg and which must
3664 : * not be freed.
3665 : * @since 3.11
3666 : */
3667 2 : const char *GDALAlgorithmGetHelpFullURL(GDALAlgorithmH hAlg)
3668 : {
3669 2 : VALIDATE_POINTER1(hAlg, __func__, nullptr);
3670 2 : return hAlg->ptr->GetHelpFullURL().c_str();
3671 : }
3672 :
3673 : /************************************************************************/
3674 : /* GDALAlgorithmHasSubAlgorithms() */
3675 : /************************************************************************/
3676 :
3677 : /** Return whether the algorithm has sub-algorithms.
3678 : *
3679 : * @param hAlg Handle to an algorithm. Must NOT be null.
3680 : * @since 3.11
3681 : */
3682 274 : bool GDALAlgorithmHasSubAlgorithms(GDALAlgorithmH hAlg)
3683 : {
3684 274 : VALIDATE_POINTER1(hAlg, __func__, false);
3685 274 : return hAlg->ptr->HasSubAlgorithms();
3686 : }
3687 :
3688 : /************************************************************************/
3689 : /* GDALAlgorithmGetSubAlgorithmNames() */
3690 : /************************************************************************/
3691 :
3692 : /** Get the names of registered algorithms.
3693 : *
3694 : * @param hAlg Handle to an algorithm. Must NOT be null.
3695 : * @return a NULL terminated list of names, which must be destroyed with
3696 : * CSLDestroy()
3697 : * @since 3.11
3698 : */
3699 2 : char **GDALAlgorithmGetSubAlgorithmNames(GDALAlgorithmH hAlg)
3700 : {
3701 2 : VALIDATE_POINTER1(hAlg, __func__, nullptr);
3702 2 : return CPLStringList(hAlg->ptr->GetSubAlgorithmNames()).StealList();
3703 : }
3704 :
3705 : /************************************************************************/
3706 : /* GDALAlgorithmInstantiateSubAlgorithm() */
3707 : /************************************************************************/
3708 :
3709 : /** Instantiate an algorithm by its name (or its alias).
3710 : *
3711 : * @param hAlg Handle to an algorithm. Must NOT be null.
3712 : * @param pszSubAlgName Algorithm name. Must NOT be null.
3713 : * @return an handle to the algorithm (to be freed with GDALAlgorithmRelease),
3714 : * or NULL if the algorithm does not exist or another error occurred.
3715 : * @since 3.11
3716 : */
3717 265 : GDALAlgorithmH GDALAlgorithmInstantiateSubAlgorithm(GDALAlgorithmH hAlg,
3718 : const char *pszSubAlgName)
3719 : {
3720 265 : VALIDATE_POINTER1(hAlg, __func__, nullptr);
3721 265 : VALIDATE_POINTER1(pszSubAlgName, __func__, nullptr);
3722 530 : auto subAlg = hAlg->ptr->InstantiateSubAlgorithm(pszSubAlgName);
3723 : return subAlg
3724 530 : ? std::make_unique<GDALAlgorithmHS>(std::move(subAlg)).release()
3725 530 : : nullptr;
3726 : }
3727 :
3728 : /************************************************************************/
3729 : /* GDALAlgorithmParseCommandLineArguments() */
3730 : /************************************************************************/
3731 :
3732 : /** Parse a command line argument, which does not include the algorithm
3733 : * name, to set the value of corresponding arguments.
3734 : *
3735 : * @param hAlg Handle to an algorithm. Must NOT be null.
3736 : * @param papszArgs NULL-terminated list of arguments, not including the algorithm name.
3737 : * @return true if successful, false otherwise
3738 : * @since 3.11
3739 : */
3740 :
3741 196 : bool GDALAlgorithmParseCommandLineArguments(GDALAlgorithmH hAlg,
3742 : CSLConstList papszArgs)
3743 : {
3744 196 : VALIDATE_POINTER1(hAlg, __func__, false);
3745 196 : return hAlg->ptr->ParseCommandLineArguments(CPLStringList(papszArgs));
3746 : }
3747 :
3748 : /************************************************************************/
3749 : /* GDALAlgorithmGetActualAlgorithm() */
3750 : /************************************************************************/
3751 :
3752 : /** Return the actual algorithm that is going to be invoked, when the
3753 : * current algorithm has sub-algorithms.
3754 : *
3755 : * Only valid after GDALAlgorithmParseCommandLineArguments() has been called.
3756 : *
3757 : * Note that the lifetime of the returned algorithm does not exceed the one of
3758 : * the hAlg instance that owns it.
3759 : *
3760 : * @param hAlg Handle to an algorithm. Must NOT be null.
3761 : * @return an handle to the algorithm (to be freed with GDALAlgorithmRelease).
3762 : * @since 3.11
3763 : */
3764 65 : GDALAlgorithmH GDALAlgorithmGetActualAlgorithm(GDALAlgorithmH hAlg)
3765 : {
3766 65 : VALIDATE_POINTER1(hAlg, __func__, nullptr);
3767 65 : return GDALAlgorithmHS::FromRef(hAlg->ptr->GetActualAlgorithm()).release();
3768 : }
3769 :
3770 : /************************************************************************/
3771 : /* GDALAlgorithmRun() */
3772 : /************************************************************************/
3773 :
3774 : /** Execute the algorithm, starting with ValidateArguments() and then
3775 : * calling RunImpl().
3776 : *
3777 : * @param hAlg Handle to an algorithm. Must NOT be null.
3778 : * @param pfnProgress Progress callback. May be null.
3779 : * @param pProgressData Progress callback user data. May be null.
3780 : * @return true if successful, false otherwise
3781 : * @since 3.11
3782 : */
3783 :
3784 246 : bool GDALAlgorithmRun(GDALAlgorithmH hAlg, GDALProgressFunc pfnProgress,
3785 : void *pProgressData)
3786 : {
3787 246 : VALIDATE_POINTER1(hAlg, __func__, false);
3788 246 : return hAlg->ptr->Run(pfnProgress, pProgressData);
3789 : }
3790 :
3791 : /************************************************************************/
3792 : /* GDALAlgorithmFinalize() */
3793 : /************************************************************************/
3794 :
3795 : /** Complete any pending actions, and return the final status.
3796 : * This is typically useful for algorithm that generate an output dataset.
3797 : *
3798 : * Note that this function does *NOT* release memory associated with the
3799 : * algorithm. GDALAlgorithmRelease() must still be called afterwards.
3800 : *
3801 : * @param hAlg Handle to an algorithm. Must NOT be null.
3802 : * @return true if successful, false otherwise
3803 : * @since 3.11
3804 : */
3805 :
3806 115 : bool GDALAlgorithmFinalize(GDALAlgorithmH hAlg)
3807 : {
3808 115 : VALIDATE_POINTER1(hAlg, __func__, false);
3809 115 : return hAlg->ptr->Finalize();
3810 : }
3811 :
3812 : /************************************************************************/
3813 : /* GDALAlgorithmGetUsageAsJSON() */
3814 : /************************************************************************/
3815 :
3816 : /** Return the usage of the algorithm as a JSON-serialized string.
3817 : *
3818 : * This can be used to dynamically generate interfaces to algorithms.
3819 : *
3820 : * @param hAlg Handle to an algorithm. Must NOT be null.
3821 : * @return a string that must be freed with CPLFree()
3822 : * @since 3.11
3823 : */
3824 4 : char *GDALAlgorithmGetUsageAsJSON(GDALAlgorithmH hAlg)
3825 : {
3826 4 : VALIDATE_POINTER1(hAlg, __func__, nullptr);
3827 4 : return CPLStrdup(hAlg->ptr->GetUsageAsJSON().c_str());
3828 : }
3829 :
3830 : /************************************************************************/
3831 : /* GDALAlgorithmGetArgNames() */
3832 : /************************************************************************/
3833 :
3834 : /** Return the list of available argument names.
3835 : *
3836 : * @param hAlg Handle to an algorithm. Must NOT be null.
3837 : * @return a NULL terminated list of names, which must be destroyed with
3838 : * CSLDestroy()
3839 : * @since 3.11
3840 : */
3841 2 : char **GDALAlgorithmGetArgNames(GDALAlgorithmH hAlg)
3842 : {
3843 2 : VALIDATE_POINTER1(hAlg, __func__, nullptr);
3844 4 : CPLStringList list;
3845 29 : for (const auto &arg : hAlg->ptr->GetArgs())
3846 27 : list.AddString(arg->GetName().c_str());
3847 2 : return list.StealList();
3848 : }
3849 :
3850 : /************************************************************************/
3851 : /* GDALAlgorithmGetArg() */
3852 : /************************************************************************/
3853 :
3854 : /** Return an argument from its name.
3855 : *
3856 : * The lifetime of the returned object does not exceed the one of hAlg.
3857 : *
3858 : * @param hAlg Handle to an algorithm. Must NOT be null.
3859 : * @param pszArgName Argument name. Must NOT be null.
3860 : * @return an argument that must be released with GDALAlgorithmArgRelease(),
3861 : * or nullptr in case of error
3862 : * @since 3.11
3863 : */
3864 326 : GDALAlgorithmArgH GDALAlgorithmGetArg(GDALAlgorithmH hAlg,
3865 : const char *pszArgName)
3866 : {
3867 326 : VALIDATE_POINTER1(hAlg, __func__, nullptr);
3868 326 : VALIDATE_POINTER1(pszArgName, __func__, nullptr);
3869 326 : auto arg = hAlg->ptr->GetArg(pszArgName);
3870 326 : if (!arg)
3871 2 : return nullptr;
3872 324 : return std::make_unique<GDALAlgorithmArgHS>(arg).release();
3873 : }
3874 :
3875 : /************************************************************************/
3876 : /* GDALAlgorithmArgRelease() */
3877 : /************************************************************************/
3878 :
3879 : /** Release a handle to an argument.
3880 : *
3881 : * @since 3.11
3882 : */
3883 324 : void GDALAlgorithmArgRelease(GDALAlgorithmArgH hArg)
3884 : {
3885 324 : delete hArg;
3886 324 : }
3887 :
3888 : /************************************************************************/
3889 : /* GDALAlgorithmArgGetName() */
3890 : /************************************************************************/
3891 :
3892 : /** Return the name of an argument.
3893 : *
3894 : * @param hArg Handle to an argument. Must NOT be null.
3895 : * @return argument name whose lifetime is bound to hArg and which must not
3896 : * be freed.
3897 : * @since 3.11
3898 : */
3899 1 : const char *GDALAlgorithmArgGetName(GDALAlgorithmArgH hArg)
3900 : {
3901 1 : VALIDATE_POINTER1(hArg, __func__, nullptr);
3902 1 : return hArg->ptr->GetName().c_str();
3903 : }
3904 :
3905 : /************************************************************************/
3906 : /* GDALAlgorithmArgGetType() */
3907 : /************************************************************************/
3908 :
3909 : /** Get the type of an argument
3910 : *
3911 : * @param hArg Handle to an argument. Must NOT be null.
3912 : * @since 3.11
3913 : */
3914 316 : GDALAlgorithmArgType GDALAlgorithmArgGetType(GDALAlgorithmArgH hArg)
3915 : {
3916 316 : VALIDATE_POINTER1(hArg, __func__, GAAT_STRING);
3917 316 : return hArg->ptr->GetType();
3918 : }
3919 :
3920 : /************************************************************************/
3921 : /* GDALAlgorithmArgGetDescription() */
3922 : /************************************************************************/
3923 :
3924 : /** Return the description of an argument.
3925 : *
3926 : * @param hArg Handle to an argument. Must NOT be null.
3927 : * @return argument descriptioin whose lifetime is bound to hArg and which must not
3928 : * be freed.
3929 : * @since 3.11
3930 : */
3931 1 : const char *GDALAlgorithmArgGetDescription(GDALAlgorithmArgH hArg)
3932 : {
3933 1 : VALIDATE_POINTER1(hArg, __func__, nullptr);
3934 1 : return hArg->ptr->GetDescription().c_str();
3935 : }
3936 :
3937 : /************************************************************************/
3938 : /* GDALAlgorithmArgGetShortName() */
3939 : /************************************************************************/
3940 :
3941 : /** Return the short name, or empty string if there is none
3942 : *
3943 : * @param hArg Handle to an argument. Must NOT be null.
3944 : * @return short name whose lifetime is bound to hArg and which must not
3945 : * be freed.
3946 : * @since 3.11
3947 : */
3948 1 : const char *GDALAlgorithmArgGetShortName(GDALAlgorithmArgH hArg)
3949 : {
3950 1 : VALIDATE_POINTER1(hArg, __func__, nullptr);
3951 1 : return hArg->ptr->GetShortName().c_str();
3952 : }
3953 :
3954 : /************************************************************************/
3955 : /* GDALAlgorithmArgGetAliases() */
3956 : /************************************************************************/
3957 :
3958 : /** Return the aliases (potentially none)
3959 : *
3960 : * @param hArg Handle to an argument. Must NOT be null.
3961 : * @return a NULL terminated list of names, which must be destroyed with
3962 : * CSLDestroy()
3963 :
3964 : * @since 3.11
3965 : */
3966 1 : char **GDALAlgorithmArgGetAliases(GDALAlgorithmArgH hArg)
3967 : {
3968 1 : VALIDATE_POINTER1(hArg, __func__, nullptr);
3969 1 : return CPLStringList(hArg->ptr->GetAliases()).StealList();
3970 : }
3971 :
3972 : /************************************************************************/
3973 : /* GDALAlgorithmArgGetMetaVar() */
3974 : /************************************************************************/
3975 :
3976 : /** Return the "meta-var" hint.
3977 : *
3978 : * By default, the meta-var value is the long name of the argument in
3979 : * upper case.
3980 : *
3981 : * @param hArg Handle to an argument. Must NOT be null.
3982 : * @return meta-var hint whose lifetime is bound to hArg and which must not
3983 : * be freed.
3984 : * @since 3.11
3985 : */
3986 1 : const char *GDALAlgorithmArgGetMetaVar(GDALAlgorithmArgH hArg)
3987 : {
3988 1 : VALIDATE_POINTER1(hArg, __func__, nullptr);
3989 1 : return hArg->ptr->GetMetaVar().c_str();
3990 : }
3991 :
3992 : /************************************************************************/
3993 : /* GDALAlgorithmArgGetCategory() */
3994 : /************************************************************************/
3995 :
3996 : /** Return the argument category
3997 : *
3998 : * GAAC_COMMON, GAAC_BASE, GAAC_ADVANCED, GAAC_ESOTERIC or a custom category.
3999 : *
4000 : * @param hArg Handle to an argument. Must NOT be null.
4001 : * @return category whose lifetime is bound to hArg and which must not
4002 : * be freed.
4003 : * @since 3.11
4004 : */
4005 1 : const char *GDALAlgorithmArgGetCategory(GDALAlgorithmArgH hArg)
4006 : {
4007 1 : VALIDATE_POINTER1(hArg, __func__, nullptr);
4008 1 : return hArg->ptr->GetCategory().c_str();
4009 : }
4010 :
4011 : /************************************************************************/
4012 : /* GDALAlgorithmArgIsPositional() */
4013 : /************************************************************************/
4014 :
4015 : /** Return if the argument is a positional one.
4016 : *
4017 : * @param hArg Handle to an argument. Must NOT be null.
4018 : * @since 3.11
4019 : */
4020 1 : bool GDALAlgorithmArgIsPositional(GDALAlgorithmArgH hArg)
4021 : {
4022 1 : VALIDATE_POINTER1(hArg, __func__, false);
4023 1 : return hArg->ptr->IsPositional();
4024 : }
4025 :
4026 : /************************************************************************/
4027 : /* GDALAlgorithmArgIsRequired() */
4028 : /************************************************************************/
4029 :
4030 : /** Return whether the argument is required. Defaults to false.
4031 : *
4032 : * @param hArg Handle to an argument. Must NOT be null.
4033 : * @since 3.11
4034 : */
4035 1 : bool GDALAlgorithmArgIsRequired(GDALAlgorithmArgH hArg)
4036 : {
4037 1 : VALIDATE_POINTER1(hArg, __func__, false);
4038 1 : return hArg->ptr->IsRequired();
4039 : }
4040 :
4041 : /************************************************************************/
4042 : /* GDALAlgorithmArgGetMinCount() */
4043 : /************************************************************************/
4044 :
4045 : /** Return the minimum number of values for the argument.
4046 : *
4047 : * Defaults to 0.
4048 : * Only applies to list type of arguments.
4049 : *
4050 : * @param hArg Handle to an argument. Must NOT be null.
4051 : * @since 3.11
4052 : */
4053 1 : int GDALAlgorithmArgGetMinCount(GDALAlgorithmArgH hArg)
4054 : {
4055 1 : VALIDATE_POINTER1(hArg, __func__, 0);
4056 1 : return hArg->ptr->GetMinCount();
4057 : }
4058 :
4059 : /************************************************************************/
4060 : /* GDALAlgorithmArgGetMaxCount() */
4061 : /************************************************************************/
4062 :
4063 : /** Return the maximum number of values for the argument.
4064 : *
4065 : * Defaults to 1 for scalar types, and INT_MAX for list types.
4066 : * Only applies to list type of arguments.
4067 : *
4068 : * @param hArg Handle to an argument. Must NOT be null.
4069 : * @since 3.11
4070 : */
4071 1 : int GDALAlgorithmArgGetMaxCount(GDALAlgorithmArgH hArg)
4072 : {
4073 1 : VALIDATE_POINTER1(hArg, __func__, 0);
4074 1 : return hArg->ptr->GetMaxCount();
4075 : }
4076 :
4077 : /************************************************************************/
4078 : /* GDALAlgorithmArgGetPackedValuesAllowed() */
4079 : /************************************************************************/
4080 :
4081 : /** Return whether, for list type of arguments, several values, space
4082 : * separated, may be specified. That is "--foo=bar,baz".
4083 : * The default is true.
4084 : *
4085 : * @param hArg Handle to an argument. Must NOT be null.
4086 : * @since 3.11
4087 : */
4088 1 : bool GDALAlgorithmArgGetPackedValuesAllowed(GDALAlgorithmArgH hArg)
4089 : {
4090 1 : VALIDATE_POINTER1(hArg, __func__, false);
4091 1 : return hArg->ptr->GetPackedValuesAllowed();
4092 : }
4093 :
4094 : /************************************************************************/
4095 : /* GDALAlgorithmArgGetRepeatedArgAllowed() */
4096 : /************************************************************************/
4097 :
4098 : /** Return whether, for list type of arguments, the argument may be
4099 : * repeated. That is "--foo=bar --foo=baz".
4100 : * The default is true.
4101 : *
4102 : * @param hArg Handle to an argument. Must NOT be null.
4103 : * @since 3.11
4104 : */
4105 1 : bool GDALAlgorithmArgGetRepeatedArgAllowed(GDALAlgorithmArgH hArg)
4106 : {
4107 1 : VALIDATE_POINTER1(hArg, __func__, false);
4108 1 : return hArg->ptr->GetRepeatedArgAllowed();
4109 : }
4110 :
4111 : /************************************************************************/
4112 : /* GDALAlgorithmArgGetChoices() */
4113 : /************************************************************************/
4114 :
4115 : /** Return the allowed values (as strings) for the argument.
4116 : *
4117 : * Only honored for GAAT_STRING and GAAT_STRING_LIST types.
4118 : *
4119 : * @param hArg Handle to an argument. Must NOT be null.
4120 : * @return a NULL terminated list of names, which must be destroyed with
4121 : * CSLDestroy()
4122 :
4123 : * @since 3.11
4124 : */
4125 1 : char **GDALAlgorithmArgGetChoices(GDALAlgorithmArgH hArg)
4126 : {
4127 1 : VALIDATE_POINTER1(hArg, __func__, nullptr);
4128 1 : return CPLStringList(hArg->ptr->GetChoices()).StealList();
4129 : }
4130 :
4131 : /************************************************************************/
4132 : /* GDALAlgorithmArgIsExplicitlySet() */
4133 : /************************************************************************/
4134 :
4135 : /** Return whether the argument value has been explicitly set with Set()
4136 : *
4137 : * @param hArg Handle to an argument. Must NOT be null.
4138 : * @since 3.11
4139 : */
4140 1 : bool GDALAlgorithmArgIsExplicitlySet(GDALAlgorithmArgH hArg)
4141 : {
4142 1 : VALIDATE_POINTER1(hArg, __func__, false);
4143 1 : return hArg->ptr->IsExplicitlySet();
4144 : }
4145 :
4146 : /************************************************************************/
4147 : /* GDALAlgorithmArgHasDefaultValue() */
4148 : /************************************************************************/
4149 :
4150 : /** Return if the argument has a declared default value.
4151 : *
4152 : * @param hArg Handle to an argument. Must NOT be null.
4153 : * @since 3.11
4154 : */
4155 1 : bool GDALAlgorithmArgHasDefaultValue(GDALAlgorithmArgH hArg)
4156 : {
4157 1 : VALIDATE_POINTER1(hArg, __func__, false);
4158 1 : return hArg->ptr->HasDefaultValue();
4159 : }
4160 :
4161 : /************************************************************************/
4162 : /* GDALAlgorithmArgIsHiddenForCLI() */
4163 : /************************************************************************/
4164 :
4165 : /** Return whether the argument must not be mentioned in CLI usage.
4166 : *
4167 : * For example, "output-value" for "gdal raster info", which is only
4168 : * meant when the algorithm is used from a non-CLI context.
4169 : *
4170 : * @param hArg Handle to an argument. Must NOT be null.
4171 : * @since 3.11
4172 : */
4173 1 : bool GDALAlgorithmArgIsHiddenForCLI(GDALAlgorithmArgH hArg)
4174 : {
4175 1 : VALIDATE_POINTER1(hArg, __func__, false);
4176 1 : return hArg->ptr->IsHiddenForCLI();
4177 : }
4178 :
4179 : /************************************************************************/
4180 : /* GDALAlgorithmArgIsOnlyForCLI() */
4181 : /************************************************************************/
4182 :
4183 : /** Return whether the argument is only for CLI usage.
4184 : *
4185 : * For example "--help"
4186 : *
4187 : * @param hArg Handle to an argument. Must NOT be null.
4188 : * @since 3.11
4189 : */
4190 1 : bool GDALAlgorithmArgIsOnlyForCLI(GDALAlgorithmArgH hArg)
4191 : {
4192 1 : VALIDATE_POINTER1(hArg, __func__, false);
4193 1 : return hArg->ptr->IsOnlyForCLI();
4194 : }
4195 :
4196 : /************************************************************************/
4197 : /* GDALAlgorithmArgIsInput() */
4198 : /************************************************************************/
4199 :
4200 : /** Indicate whether the value of the argument is read-only during the
4201 : * execution of the algorithm.
4202 : *
4203 : * Default is true.
4204 : *
4205 : * @param hArg Handle to an argument. Must NOT be null.
4206 : * @since 3.11
4207 : */
4208 1 : bool GDALAlgorithmArgIsInput(GDALAlgorithmArgH hArg)
4209 : {
4210 1 : VALIDATE_POINTER1(hArg, __func__, false);
4211 1 : return hArg->ptr->IsInput();
4212 : }
4213 :
4214 : /************************************************************************/
4215 : /* GDALAlgorithmArgIsOutput() */
4216 : /************************************************************************/
4217 :
4218 : /** Return whether (at least part of) the value of the argument is set
4219 : * during the execution of the algorithm.
4220 : *
4221 : * For example, "output-value" for "gdal raster info"
4222 : * Default is false.
4223 : * An argument may return both IsInput() and IsOutput() as true.
4224 : * For example the "gdal raster convert" algorithm consumes the dataset
4225 : * name of its "output" argument, and sets the dataset object during its
4226 : * execution.
4227 : *
4228 : * @param hArg Handle to an argument. Must NOT be null.
4229 : * @since 3.11
4230 : */
4231 1 : bool GDALAlgorithmArgIsOutput(GDALAlgorithmArgH hArg)
4232 : {
4233 1 : VALIDATE_POINTER1(hArg, __func__, false);
4234 1 : return hArg->ptr->IsOutput();
4235 : }
4236 :
4237 : /************************************************************************/
4238 : /* GDALAlgorithmArgGetMutualExclusionGroup() */
4239 : /************************************************************************/
4240 :
4241 : /** Return the name of the mutual exclusion group to which this argument
4242 : * belongs to.
4243 : *
4244 : * Or empty string if it does not belong to any exclusion group.
4245 : *
4246 : * @param hArg Handle to an argument. Must NOT be null.
4247 : * @return string whose lifetime is bound to hArg and which must not
4248 : * be freed.
4249 : * @since 3.11
4250 : */
4251 1 : const char *GDALAlgorithmArgGetMutualExclusionGroup(GDALAlgorithmArgH hArg)
4252 : {
4253 1 : VALIDATE_POINTER1(hArg, __func__, nullptr);
4254 1 : return hArg->ptr->GetMutualExclusionGroup().c_str();
4255 : }
4256 :
4257 : /************************************************************************/
4258 : /* GDALAlgorithmArgGetAsBoolean() */
4259 : /************************************************************************/
4260 :
4261 : /** Return the argument value as a boolean.
4262 : *
4263 : * Must only be called on arguments whose type is GAAT_BOOLEAN.
4264 : *
4265 : * @param hArg Handle to an argument. Must NOT be null.
4266 : * @since 3.11
4267 : */
4268 4 : bool GDALAlgorithmArgGetAsBoolean(GDALAlgorithmArgH hArg)
4269 : {
4270 4 : VALIDATE_POINTER1(hArg, __func__, false);
4271 4 : if (hArg->ptr->GetType() != GAAT_BOOLEAN)
4272 : {
4273 1 : CPLError(CE_Failure, CPLE_AppDefined,
4274 : "%s must only be called on arguments of type GAAT_BOOLEAN",
4275 : __func__);
4276 1 : return false;
4277 : }
4278 3 : return hArg->ptr->Get<bool>();
4279 : }
4280 :
4281 : /************************************************************************/
4282 : /* GDALAlgorithmArgGetAsBoolean() */
4283 : /************************************************************************/
4284 :
4285 : /** Return the argument value as a string.
4286 : *
4287 : * Must only be called on arguments whose type is GAAT_STRING.
4288 : *
4289 : * @param hArg Handle to an argument. Must NOT be null.
4290 : * @return string whose lifetime is bound to hArg and which must not
4291 : * be freed.
4292 : * @since 3.11
4293 : */
4294 26 : const char *GDALAlgorithmArgGetAsString(GDALAlgorithmArgH hArg)
4295 : {
4296 26 : VALIDATE_POINTER1(hArg, __func__, nullptr);
4297 26 : if (hArg->ptr->GetType() != GAAT_STRING)
4298 : {
4299 1 : CPLError(CE_Failure, CPLE_AppDefined,
4300 : "%s must only be called on arguments of type GAAT_STRING",
4301 : __func__);
4302 1 : return nullptr;
4303 : }
4304 25 : return hArg->ptr->Get<std::string>().c_str();
4305 : }
4306 :
4307 : /************************************************************************/
4308 : /* GDALAlgorithmArgGetAsDatasetValue() */
4309 : /************************************************************************/
4310 :
4311 : /** Return the argument value as a GDALArgDatasetValueH.
4312 : *
4313 : * Must only be called on arguments whose type is GAAT_DATASET
4314 : *
4315 : * @param hArg Handle to an argument. Must NOT be null.
4316 : * @return handle to a GDALArgDatasetValue that must be released with
4317 : * GDALArgDatasetValueRelease(). The lifetime of that handle does not exceed
4318 : * the one of hArg.
4319 : * @since 3.11
4320 : */
4321 164 : GDALArgDatasetValueH GDALAlgorithmArgGetAsDatasetValue(GDALAlgorithmArgH hArg)
4322 : {
4323 164 : VALIDATE_POINTER1(hArg, __func__, nullptr);
4324 164 : if (hArg->ptr->GetType() != GAAT_DATASET)
4325 : {
4326 1 : CPLError(CE_Failure, CPLE_AppDefined,
4327 : "%s must only be called on arguments of type GAAT_DATASET",
4328 : __func__);
4329 1 : return nullptr;
4330 : }
4331 163 : return std::make_unique<GDALArgDatasetValueHS>(
4332 326 : &(hArg->ptr->Get<GDALArgDatasetValue>()))
4333 163 : .release();
4334 : }
4335 :
4336 : /************************************************************************/
4337 : /* GDALAlgorithmArgGetAsInteger() */
4338 : /************************************************************************/
4339 :
4340 : /** Return the argument value as a integer.
4341 : *
4342 : * Must only be called on arguments whose type is GAAT_INTEGER
4343 : *
4344 : * @param hArg Handle to an argument. Must NOT be null.
4345 : * @since 3.11
4346 : */
4347 2 : int GDALAlgorithmArgGetAsInteger(GDALAlgorithmArgH hArg)
4348 : {
4349 2 : VALIDATE_POINTER1(hArg, __func__, 0);
4350 2 : if (hArg->ptr->GetType() != GAAT_INTEGER)
4351 : {
4352 1 : CPLError(CE_Failure, CPLE_AppDefined,
4353 : "%s must only be called on arguments of type GAAT_INTEGER",
4354 : __func__);
4355 1 : return 0;
4356 : }
4357 1 : return hArg->ptr->Get<int>();
4358 : }
4359 :
4360 : /************************************************************************/
4361 : /* GDALAlgorithmArgGetAsDouble() */
4362 : /************************************************************************/
4363 :
4364 : /** Return the argument value as a double.
4365 : *
4366 : * Must only be called on arguments whose type is GAAT_REAL
4367 : *
4368 : * @param hArg Handle to an argument. Must NOT be null.
4369 : * @since 3.11
4370 : */
4371 2 : double GDALAlgorithmArgGetAsDouble(GDALAlgorithmArgH hArg)
4372 : {
4373 2 : VALIDATE_POINTER1(hArg, __func__, 0);
4374 2 : if (hArg->ptr->GetType() != GAAT_REAL)
4375 : {
4376 1 : CPLError(CE_Failure, CPLE_AppDefined,
4377 : "%s must only be called on arguments of type GAAT_REAL",
4378 : __func__);
4379 1 : return 0;
4380 : }
4381 1 : return hArg->ptr->Get<double>();
4382 : }
4383 :
4384 : /************************************************************************/
4385 : /* GDALAlgorithmArgGetAsStringList() */
4386 : /************************************************************************/
4387 :
4388 : /** Return the argument value as a double.
4389 : *
4390 : * Must only be called on arguments whose type is GAAT_STRING_LIST.
4391 : *
4392 : * @param hArg Handle to an argument. Must NOT be null.
4393 : * @return a NULL terminated list of names, which must be destroyed with
4394 : * CSLDestroy()
4395 :
4396 : * @since 3.11
4397 : */
4398 2 : char **GDALAlgorithmArgGetAsStringList(GDALAlgorithmArgH hArg)
4399 : {
4400 2 : VALIDATE_POINTER1(hArg, __func__, nullptr);
4401 2 : if (hArg->ptr->GetType() != GAAT_STRING_LIST)
4402 : {
4403 1 : CPLError(CE_Failure, CPLE_AppDefined,
4404 : "%s must only be called on arguments of type GAAT_STRING_LIST",
4405 : __func__);
4406 1 : return nullptr;
4407 : }
4408 2 : return CPLStringList(hArg->ptr->Get<std::vector<std::string>>())
4409 1 : .StealList();
4410 : }
4411 :
4412 : /************************************************************************/
4413 : /* GDALAlgorithmArgGetAsIntegerList() */
4414 : /************************************************************************/
4415 :
4416 : /** Return the argument value as a integer.
4417 : *
4418 : * Must only be called on arguments whose type is GAAT_INTEGER
4419 : *
4420 : * @param hArg Handle to an argument. Must NOT be null.
4421 : * @param[out] pnCount Pointer to the number of values in the list. Must NOT be null.
4422 : * @since 3.11
4423 : */
4424 2 : const int *GDALAlgorithmArgGetAsIntegerList(GDALAlgorithmArgH hArg,
4425 : size_t *pnCount)
4426 : {
4427 2 : VALIDATE_POINTER1(hArg, __func__, nullptr);
4428 2 : VALIDATE_POINTER1(pnCount, __func__, nullptr);
4429 2 : if (hArg->ptr->GetType() != GAAT_INTEGER_LIST)
4430 : {
4431 1 : CPLError(
4432 : CE_Failure, CPLE_AppDefined,
4433 : "%s must only be called on arguments of type GAAT_INTEGER_LIST",
4434 : __func__);
4435 1 : *pnCount = 0;
4436 1 : return nullptr;
4437 : }
4438 1 : const auto &val = hArg->ptr->Get<std::vector<int>>();
4439 1 : *pnCount = val.size();
4440 1 : return val.data();
4441 : }
4442 :
4443 : /************************************************************************/
4444 : /* GDALAlgorithmArgGetAsDoubleList() */
4445 : /************************************************************************/
4446 :
4447 : /** Return the argument value as a integer.
4448 : *
4449 : * Must only be called on arguments whose type is GAAT_INTEGER
4450 : *
4451 : * @param hArg Handle to an argument. Must NOT be null.
4452 : * @param[out] pnCount Pointer to the number of values in the list. Must NOT be null.
4453 : * @since 3.11
4454 : */
4455 2 : const double *GDALAlgorithmArgGetAsDoubleList(GDALAlgorithmArgH hArg,
4456 : size_t *pnCount)
4457 : {
4458 2 : VALIDATE_POINTER1(hArg, __func__, nullptr);
4459 2 : VALIDATE_POINTER1(pnCount, __func__, nullptr);
4460 2 : if (hArg->ptr->GetType() != GAAT_REAL_LIST)
4461 : {
4462 1 : CPLError(CE_Failure, CPLE_AppDefined,
4463 : "%s must only be called on arguments of type GAAT_REAL_LIST",
4464 : __func__);
4465 1 : *pnCount = 0;
4466 1 : return nullptr;
4467 : }
4468 1 : const auto &val = hArg->ptr->Get<std::vector<double>>();
4469 1 : *pnCount = val.size();
4470 1 : return val.data();
4471 : }
4472 :
4473 : /************************************************************************/
4474 : /* GDALAlgorithmArgSetAsBoolean() */
4475 : /************************************************************************/
4476 :
4477 : /** Set the value for a GAAT_BOOLEAN argument.
4478 : *
4479 : * It cannot be called several times for a given argument.
4480 : * Validation checks and other actions are run.
4481 : *
4482 : * @param hArg Handle to an argument. Must NOT be null.
4483 : * @param value value.
4484 : * @return true if success.
4485 : * @since 3.11
4486 : */
4487 :
4488 8 : bool GDALAlgorithmArgSetAsBoolean(GDALAlgorithmArgH hArg, bool value)
4489 : {
4490 8 : VALIDATE_POINTER1(hArg, __func__, false);
4491 8 : return hArg->ptr->Set(value);
4492 : }
4493 :
4494 : /************************************************************************/
4495 : /* GDALAlgorithmArgSetAsString() */
4496 : /************************************************************************/
4497 :
4498 : /** Set the value for a GAAT_STRING argument.
4499 : *
4500 : * It cannot be called several times for a given argument.
4501 : * Validation checks and other actions are run.
4502 : *
4503 : * @param hArg Handle to an argument. Must NOT be null.
4504 : * @param value value (may be null)
4505 : * @return true if success.
4506 : * @since 3.11
4507 : */
4508 :
4509 25 : bool GDALAlgorithmArgSetAsString(GDALAlgorithmArgH hArg, const char *value)
4510 : {
4511 25 : VALIDATE_POINTER1(hArg, __func__, false);
4512 25 : return hArg->ptr->Set(value ? value : "");
4513 : }
4514 :
4515 : /************************************************************************/
4516 : /* GDALAlgorithmArgSetAsInteger() */
4517 : /************************************************************************/
4518 :
4519 : /** Set the value for a GAAT_INTEGER (or GAAT_REAL) argument.
4520 : *
4521 : * It cannot be called several times for a given argument.
4522 : * Validation checks and other actions are run.
4523 : *
4524 : * @param hArg Handle to an argument. Must NOT be null.
4525 : * @param value value.
4526 : * @return true if success.
4527 : * @since 3.11
4528 : */
4529 :
4530 5 : bool GDALAlgorithmArgSetAsInteger(GDALAlgorithmArgH hArg, int value)
4531 : {
4532 5 : VALIDATE_POINTER1(hArg, __func__, false);
4533 5 : return hArg->ptr->Set(value);
4534 : }
4535 :
4536 : /************************************************************************/
4537 : /* GDALAlgorithmArgSetAsDouble() */
4538 : /************************************************************************/
4539 :
4540 : /** Set the value for a GAAT_REAL argument.
4541 : *
4542 : * It cannot be called several times for a given argument.
4543 : * Validation checks and other actions are run.
4544 : *
4545 : * @param hArg Handle to an argument. Must NOT be null.
4546 : * @param value value.
4547 : * @return true if success.
4548 : * @since 3.11
4549 : */
4550 :
4551 1 : bool GDALAlgorithmArgSetAsDouble(GDALAlgorithmArgH hArg, double value)
4552 : {
4553 1 : VALIDATE_POINTER1(hArg, __func__, false);
4554 1 : return hArg->ptr->Set(value);
4555 : }
4556 :
4557 : /************************************************************************/
4558 : /* GDALAlgorithmArgSetAsDatasetValue() */
4559 : /************************************************************************/
4560 :
4561 : /** Set the value for a GAAT_DATASET argument.
4562 : *
4563 : * It cannot be called several times for a given argument.
4564 : * Validation checks and other actions are run.
4565 : *
4566 : * @param hArg Handle to an argument. Must NOT be null.
4567 : * @param value Handle to a GDALArgDatasetValue. Must NOT be null.
4568 : * @return true if success.
4569 : * @since 3.11
4570 : */
4571 2 : bool GDALAlgorithmArgSetAsDatasetValue(GDALAlgorithmArgH hArg,
4572 : GDALArgDatasetValueH value)
4573 : {
4574 2 : VALIDATE_POINTER1(hArg, __func__, false);
4575 2 : VALIDATE_POINTER1(value, __func__, false);
4576 2 : return hArg->ptr->SetFrom(*(value->ptr));
4577 : }
4578 :
4579 : /************************************************************************/
4580 : /* GDALAlgorithmArgSetDataset() */
4581 : /************************************************************************/
4582 :
4583 : /** Set dataset object, increasing its reference counter.
4584 : *
4585 : * @param hArg Handle to an argument. Must NOT be null.
4586 : * @param hDS Dataset object. May be null.
4587 : * @return true if success.
4588 : * @since 3.11
4589 : */
4590 :
4591 3 : bool GDALAlgorithmArgSetDataset(GDALAlgorithmArgH hArg, GDALDatasetH hDS)
4592 : {
4593 3 : VALIDATE_POINTER1(hArg, __func__, false);
4594 3 : return hArg->ptr->Set(GDALDataset::FromHandle(hDS));
4595 : }
4596 :
4597 : /************************************************************************/
4598 : /* GDALAlgorithmArgSetAsStringList() */
4599 : /************************************************************************/
4600 :
4601 : /** Set the value for a GAAT_STRING_LIST argument.
4602 : *
4603 : * It cannot be called several times for a given argument.
4604 : * Validation checks and other actions are run.
4605 : *
4606 : * @param hArg Handle to an argument. Must NOT be null.
4607 : * @param value value as a NULL terminated list (may be null)
4608 : * @return true if success.
4609 : * @since 3.11
4610 : */
4611 :
4612 70 : bool GDALAlgorithmArgSetAsStringList(GDALAlgorithmArgH hArg, CSLConstList value)
4613 : {
4614 70 : VALIDATE_POINTER1(hArg, __func__, false);
4615 70 : return hArg->ptr->Set(
4616 140 : static_cast<std::vector<std::string>>(CPLStringList(value)));
4617 : }
4618 :
4619 : /************************************************************************/
4620 : /* GDALAlgorithmArgSetAsIntegerList() */
4621 : /************************************************************************/
4622 :
4623 : /** Set the value for a GAAT_INTEGER_LIST argument.
4624 : *
4625 : * It cannot be called several times for a given argument.
4626 : * Validation checks and other actions are run.
4627 : *
4628 : * @param hArg Handle to an argument. Must NOT be null.
4629 : * @param nCount Number of values in pnValues.
4630 : * @param pnValues Pointer to an array of integer values of size nCount.
4631 : * @return true if success.
4632 : * @since 3.11
4633 : */
4634 4 : bool GDALAlgorithmArgSetAsIntegerList(GDALAlgorithmArgH hArg, size_t nCount,
4635 : const int *pnValues)
4636 : {
4637 4 : VALIDATE_POINTER1(hArg, __func__, false);
4638 4 : return hArg->ptr->Set(std::vector<int>(pnValues, pnValues + nCount));
4639 : }
4640 :
4641 : /************************************************************************/
4642 : /* GDALAlgorithmArgSetAsDoubleList() */
4643 : /************************************************************************/
4644 :
4645 : /** Set the value for a GAAT_REAL_LIST argument.
4646 : *
4647 : * It cannot be called several times for a given argument.
4648 : * Validation checks and other actions are run.
4649 : *
4650 : * @param hArg Handle to an argument. Must NOT be null.
4651 : * @param nCount Number of values in pnValues.
4652 : * @param pnValues Pointer to an array of double values of size nCount.
4653 : * @return true if success.
4654 : * @since 3.11
4655 : */
4656 6 : bool GDALAlgorithmArgSetAsDoubleList(GDALAlgorithmArgH hArg, size_t nCount,
4657 : const double *pnValues)
4658 : {
4659 6 : VALIDATE_POINTER1(hArg, __func__, false);
4660 6 : return hArg->ptr->Set(std::vector<double>(pnValues, pnValues + nCount));
4661 : }
4662 :
4663 : /************************************************************************/
4664 : /* GDALAlgorithmArgSetDatasets() */
4665 : /************************************************************************/
4666 :
4667 : /** Set dataset objects to a GAAT_DATASET_LIST argument, increasing their reference counter.
4668 : *
4669 : * @param hArg Handle to an argument. Must NOT be null.
4670 : * @param nCount Number of values in pnValues.
4671 : * @param pahDS Pointer to an array of dataset of size nCount.
4672 : * @return true if success.
4673 : * @since 3.11
4674 : */
4675 :
4676 10 : bool GDALAlgorithmArgSetDatasets(GDALAlgorithmArgH hArg, size_t nCount,
4677 : GDALDatasetH *pahDS)
4678 : {
4679 10 : VALIDATE_POINTER1(hArg, __func__, false);
4680 20 : std::vector<GDALArgDatasetValue> values;
4681 28 : for (size_t i = 0; i < nCount; ++i)
4682 : {
4683 18 : values.emplace_back(GDALDataset::FromHandle(pahDS[i]));
4684 : }
4685 10 : return hArg->ptr->Set(std::move(values));
4686 : }
4687 :
4688 : /************************************************************************/
4689 : /* GDALAlgorithmArgSetDatasetNames() */
4690 : /************************************************************************/
4691 :
4692 : /** Set dataset names to a GAAT_DATASET_LIST argument.
4693 : *
4694 : * @param hArg Handle to an argument. Must NOT be null.
4695 : * @param names Dataset names as a NULL terminated list (may be null)
4696 : * @return true if success.
4697 : * @since 3.11
4698 : */
4699 :
4700 7 : bool GDALAlgorithmArgSetDatasetNames(GDALAlgorithmArgH hArg, CSLConstList names)
4701 : {
4702 7 : VALIDATE_POINTER1(hArg, __func__, false);
4703 14 : std::vector<GDALArgDatasetValue> values;
4704 14 : for (size_t i = 0; names[i]; ++i)
4705 : {
4706 7 : values.emplace_back(names[i]);
4707 : }
4708 7 : return hArg->ptr->Set(std::move(values));
4709 : }
4710 :
4711 : /************************************************************************/
4712 : /* GDALArgDatasetValueCreate() */
4713 : /************************************************************************/
4714 :
4715 : /** Instantiate an empty GDALArgDatasetValue
4716 : *
4717 : * @return new handle to free with GDALArgDatasetValueRelease()
4718 : * @since 3.11
4719 : */
4720 1 : GDALArgDatasetValueH GDALArgDatasetValueCreate()
4721 : {
4722 1 : return std::make_unique<GDALArgDatasetValueHS>().release();
4723 : }
4724 :
4725 : /************************************************************************/
4726 : /* GDALArgDatasetValueRelease() */
4727 : /************************************************************************/
4728 :
4729 : /** Release a handle to a GDALArgDatasetValue
4730 : *
4731 : * @since 3.11
4732 : */
4733 164 : void GDALArgDatasetValueRelease(GDALArgDatasetValueH hValue)
4734 : {
4735 164 : delete hValue;
4736 164 : }
4737 :
4738 : /************************************************************************/
4739 : /* GDALArgDatasetValueGetName() */
4740 : /************************************************************************/
4741 :
4742 : /** Return the name component of the GDALArgDatasetValue
4743 : *
4744 : * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4745 : * @return string whose lifetime is bound to hAlg and which must not
4746 : * be freed.
4747 : * @since 3.11
4748 : */
4749 1 : const char *GDALArgDatasetValueGetName(GDALArgDatasetValueH hValue)
4750 : {
4751 1 : VALIDATE_POINTER1(hValue, __func__, nullptr);
4752 1 : return hValue->ptr->GetName().c_str();
4753 : }
4754 :
4755 : /************************************************************************/
4756 : /* GDALArgDatasetValueGetDatasetRef() */
4757 : /************************************************************************/
4758 :
4759 : /** Return the dataset component of the GDALArgDatasetValue.
4760 : *
4761 : * This does not modify the reference counter, hence the lifetime of the
4762 : * returned object is not guaranteed to exceed the one of hValue.
4763 : *
4764 : * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4765 : * @since 3.11
4766 : */
4767 3 : GDALDatasetH GDALArgDatasetValueGetDatasetRef(GDALArgDatasetValueH hValue)
4768 : {
4769 3 : VALIDATE_POINTER1(hValue, __func__, nullptr);
4770 3 : return GDALDataset::ToHandle(hValue->ptr->GetDatasetRef());
4771 : }
4772 :
4773 : /************************************************************************/
4774 : /* GDALArgDatasetValueGetDatasetIncreaseRefCount() */
4775 : /************************************************************************/
4776 :
4777 : /** Return the dataset component of the GDALArgDatasetValue, and increase its
4778 : * reference count if not null. Once done with the dataset, the caller should
4779 : * call GDALReleaseDataset().
4780 : *
4781 : * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4782 : * @since 3.11
4783 : */
4784 : GDALDatasetH
4785 45 : GDALArgDatasetValueGetDatasetIncreaseRefCount(GDALArgDatasetValueH hValue)
4786 : {
4787 45 : VALIDATE_POINTER1(hValue, __func__, nullptr);
4788 45 : return GDALDataset::ToHandle(hValue->ptr->GetDatasetIncreaseRefCount());
4789 : }
4790 :
4791 : /************************************************************************/
4792 : /* GDALArgDatasetValueGetType() */
4793 : /************************************************************************/
4794 :
4795 : /** Get which type of dataset is allowed / generated.
4796 : *
4797 : * Binary-or combination of GDAL_OF_RASTER, GDAL_OF_VECTOR and
4798 : * GDAL_OF_MULTIDIM_RASTER.
4799 : *
4800 : * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4801 : * @since 3.11
4802 : */
4803 1 : GDALArgDatasetValueType GDALArgDatasetValueGetType(GDALArgDatasetValueH hValue)
4804 : {
4805 1 : VALIDATE_POINTER1(hValue, __func__, 0);
4806 1 : return hValue->ptr->GetType();
4807 : }
4808 :
4809 : /************************************************************************/
4810 : /* GDALArgDatasetValueGetInputFlags() */
4811 : /************************************************************************/
4812 :
4813 : /** Indicates which components among name and dataset are accepted as
4814 : * input, when this argument serves as an input.
4815 : *
4816 : * If the GADV_NAME bit is set, it indicates a dataset name is accepted as
4817 : * input.
4818 : * If the GADV_OBJECT bit is set, it indicates a dataset object is
4819 : * accepted as input.
4820 : * If both bits are set, the algorithm can accept either a name or a dataset
4821 : * object.
4822 : *
4823 : * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4824 : * @return string whose lifetime is bound to hAlg and which must not
4825 : * be freed.
4826 : * @since 3.11
4827 : */
4828 1 : int GDALArgDatasetValueGetInputFlags(GDALArgDatasetValueH hValue)
4829 : {
4830 1 : VALIDATE_POINTER1(hValue, __func__, 0);
4831 1 : return hValue->ptr->GetInputFlags();
4832 : }
4833 :
4834 : /************************************************************************/
4835 : /* GDALArgDatasetValueGetOutputFlags() */
4836 : /************************************************************************/
4837 :
4838 : /** Indicates which components among name and dataset are modified,
4839 : * when this argument serves as an output.
4840 : *
4841 : * If the GADV_NAME bit is set, it indicates a dataset name is generated as
4842 : * output (that is the algorithm will generate the name. Rarely used).
4843 : * If the GADV_OBJECT bit is set, it indicates a dataset object is
4844 : * generated as output, and available for use after the algorithm has
4845 : * completed.
4846 : *
4847 : * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4848 : * @return string whose lifetime is bound to hAlg and which must not
4849 : * be freed.
4850 : * @since 3.11
4851 : */
4852 1 : int GDALArgDatasetValueGetOutputFlags(GDALArgDatasetValueH hValue)
4853 : {
4854 1 : VALIDATE_POINTER1(hValue, __func__, 0);
4855 1 : return hValue->ptr->GetOutputFlags();
4856 : }
4857 :
4858 : /************************************************************************/
4859 : /* GDALArgDatasetValueSetName() */
4860 : /************************************************************************/
4861 :
4862 : /** Set dataset name
4863 : *
4864 : * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4865 : * @param pszName Dataset name. May be null.
4866 : * @since 3.11
4867 : */
4868 :
4869 58 : void GDALArgDatasetValueSetName(GDALArgDatasetValueH hValue,
4870 : const char *pszName)
4871 : {
4872 58 : VALIDATE_POINTER0(hValue, __func__);
4873 58 : hValue->ptr->Set(pszName ? pszName : "");
4874 : }
4875 :
4876 : /************************************************************************/
4877 : /* GDALArgDatasetValueSetDataset() */
4878 : /************************************************************************/
4879 :
4880 : /** Set dataset object, increasing its reference counter.
4881 : *
4882 : * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4883 : * @param hDS Dataset object. May be null.
4884 : * @since 3.11
4885 : */
4886 :
4887 63 : void GDALArgDatasetValueSetDataset(GDALArgDatasetValueH hValue,
4888 : GDALDatasetH hDS)
4889 : {
4890 63 : VALIDATE_POINTER0(hValue, __func__);
4891 63 : hValue->ptr->Set(GDALDataset::FromHandle(hDS));
4892 : }
|