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