• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 13899354245

17 Mar 2025 12:24PM UTC coverage: 70.457% (+0.02%) from 70.436%
13899354245

Pull #11951

github

web-flow
Merge c67e11463 into 05516a020
Pull Request #11951: Doc: Build docs using CMake

554033 of 786337 relevant lines covered (70.46%)

220670.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.08
/gcore/gdalalgorithm.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  GDALAlgorithm class
5
 * Author:   Even Rouault <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12

13
#include "cpl_port.h"
14
#include "cpl_conv.h"
15
#include "cpl_error.h"
16
#include "cpl_json.h"
17
#include "cpl_minixml.h"
18

19
#include "gdalalgorithm.h"
20
#include "gdal_priv.h"
21

22
#include <algorithm>
23
#include <cassert>
24
#include <cerrno>
25
#include <cstdlib>
26
#include <map>
27

28
#ifndef _
29
#define _(x) (x)
30
#endif
31

32
constexpr const char *GDAL_ARG_NAME_INPUT_FORMAT = "input-format";
33

34
constexpr const char *GDAL_ARG_NAME_OUTPUT_FORMAT = "output-format";
35

36
constexpr const char *GDAL_ARG_NAME_OUTPUT_DATA_TYPE = "output-data-type";
37

38
constexpr const char *GDAL_ARG_NAME_OPEN_OPTION = "open-option";
39

40
//! @cond Doxygen_Suppress
41
struct GDALAlgorithmArgHS
42
{
43
    GDALAlgorithmArg *ptr = nullptr;
44

45
    explicit GDALAlgorithmArgHS(GDALAlgorithmArg *arg) : ptr(arg)
324✔
46
    {
47
    }
324✔
48
};
49

50
//! @endcond
51

52
//! @cond Doxygen_Suppress
53
struct GDALArgDatasetValueHS
54
{
55
    GDALArgDatasetValue val{};
56
    GDALArgDatasetValue *ptr = nullptr;
57

58
    GDALArgDatasetValueHS() : ptr(&val)
1✔
59
    {
60
    }
1✔
61

62
    explicit GDALArgDatasetValueHS(GDALArgDatasetValue *arg) : ptr(arg)
163✔
63
    {
64
    }
163✔
65

66
    GDALArgDatasetValueHS(const GDALArgDatasetValueHS &) = delete;
67
    GDALArgDatasetValueHS &operator=(const GDALArgDatasetValueHS &) = delete;
68
};
69

70
//! @endcond
71

72
/************************************************************************/
73
/*                     GDALAlgorithmArgTypeIsList()                     */
74
/************************************************************************/
75

76
bool GDALAlgorithmArgTypeIsList(GDALAlgorithmArgType type)
20,842✔
77
{
78
    switch (type)
20,842✔
79
    {
80
        case GAAT_BOOLEAN:
14,676✔
81
        case GAAT_STRING:
82
        case GAAT_INTEGER:
83
        case GAAT_REAL:
84
        case GAAT_DATASET:
85
            break;
14,676✔
86

87
        case GAAT_STRING_LIST:
6,166✔
88
        case GAAT_INTEGER_LIST:
89
        case GAAT_REAL_LIST:
90
        case GAAT_DATASET_LIST:
91
            return true;
6,166✔
92
    }
93

94
    return false;
14,676✔
95
}
96

97
/************************************************************************/
98
/*                     GDALAlgorithmArgTypeName()                       */
99
/************************************************************************/
100

101
const char *GDALAlgorithmArgTypeName(GDALAlgorithmArgType type)
710✔
102
{
103
    switch (type)
710✔
104
    {
105
        case GAAT_BOOLEAN:
158✔
106
            break;
158✔
107
        case GAAT_STRING:
181✔
108
            return "string";
181✔
109
        case GAAT_INTEGER:
15✔
110
            return "integer";
15✔
111
        case GAAT_REAL:
11✔
112
            return "real";
11✔
113
        case GAAT_DATASET:
92✔
114
            return "dataset";
92✔
115
        case GAAT_STRING_LIST:
173✔
116
            return "string_list";
173✔
117
        case GAAT_INTEGER_LIST:
23✔
118
            return "integer_list";
23✔
119
        case GAAT_REAL_LIST:
51✔
120
            return "real_list";
51✔
121
        case GAAT_DATASET_LIST:
6✔
122
            return "dataset_list";
6✔
123
    }
124

125
    return "boolean";
158✔
126
}
127

128
/************************************************************************/
129
/*                     GDALArgDatasetValueTypeName()                    */
130
/************************************************************************/
131

132
std::string GDALArgDatasetValueTypeName(GDALArgDatasetValueType type)
1,108✔
133
{
134
    std::string ret;
1,108✔
135
    if ((type & GDAL_OF_RASTER) != 0)
1,108✔
136
        ret = "raster";
557✔
137
    if ((type & GDAL_OF_VECTOR) != 0)
1,108✔
138
    {
139
        if (!ret.empty())
636✔
140
        {
141
            if ((type & GDAL_OF_MULTIDIM_RASTER) != 0)
86✔
142
                ret += ", ";
79✔
143
            else
144
                ret += " or ";
7✔
145
        }
146
        ret += "vector";
636✔
147
    }
148
    if ((type & GDAL_OF_MULTIDIM_RASTER) != 0)
1,108✔
149
    {
150
        if (!ret.empty())
82✔
151
        {
152
            ret += " or ";
81✔
153
        }
154
        ret += "multidimensional raster";
82✔
155
    }
156
    return ret;
1,108✔
157
}
158

159
/************************************************************************/
160
/*                     GDALAlgorithmArgDecl()                           */
161
/************************************************************************/
162

163
// cppcheck-suppress uninitMemberVar
164
GDALAlgorithmArgDecl::GDALAlgorithmArgDecl(const std::string &longName,
16,770✔
165
                                           char chShortName,
166
                                           const std::string &description,
167
                                           GDALAlgorithmArgType type)
16,770✔
168
    : m_longName(longName),
169
      m_shortName(chShortName ? std::string(&chShortName, 1) : std::string()),
16,770✔
170
      m_description(description), m_type(type),
171
      m_metaVar(CPLString(m_type == GAAT_BOOLEAN ? std::string() : longName)
33,540✔
172
                    .toupper()),
16,770✔
173
      m_maxCount(GDALAlgorithmArgTypeIsList(type) ? UNBOUNDED : 1)
50,310✔
174
{
175
    if (m_type == GAAT_BOOLEAN)
16,770✔
176
    {
177
        m_defaultValue = false;
8,897✔
178
    }
179
}
16,770✔
180

181
/************************************************************************/
182
/*               GDALAlgorithmArgDecl::SetMinCount()                    */
183
/************************************************************************/
184

185
GDALAlgorithmArgDecl &GDALAlgorithmArgDecl::SetMinCount(int count)
487✔
186
{
187
    if (!GDALAlgorithmArgTypeIsList(m_type))
487✔
188
    {
189
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
190
                 "SetMinCount() illegal on scalar argument '%s'",
191
                 GetName().c_str());
1✔
192
    }
193
    else
194
    {
195
        m_minCount = count;
486✔
196
    }
197
    return *this;
487✔
198
}
199

200
/************************************************************************/
201
/*               GDALAlgorithmArgDecl::SetMaxCount()                    */
202
/************************************************************************/
203

204
GDALAlgorithmArgDecl &GDALAlgorithmArgDecl::SetMaxCount(int count)
332✔
205
{
206
    if (!GDALAlgorithmArgTypeIsList(m_type))
332✔
207
    {
208
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
209
                 "SetMaxCount() illegal on scalar argument '%s'",
210
                 GetName().c_str());
1✔
211
    }
212
    else
213
    {
214
        m_maxCount = count;
331✔
215
    }
216
    return *this;
332✔
217
}
218

219
/************************************************************************/
220
/*                         GDALAlgorithmArg::Set()                      */
221
/************************************************************************/
222

223
bool GDALAlgorithmArg::Set(bool value)
153✔
224
{
225
    if (m_decl.GetType() != GAAT_BOOLEAN)
153✔
226
    {
227
        CPLError(
14✔
228
            CE_Failure, CPLE_AppDefined,
229
            "Calling Set(bool) on argument '%s' of type %s is not supported",
230
            GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
7✔
231
        return false;
7✔
232
    }
233
    return SetInternal(value);
146✔
234
}
235

236
bool GDALAlgorithmArg::ProcessString(std::string &value) const
260✔
237
{
238
    if (m_decl.IsReadFromFileAtSyntaxAllowed() && !value.empty() &&
281✔
239
        value.front() == '@')
21✔
240
    {
241
        GByte *pabyData = nullptr;
2✔
242
        if (VSIIngestFile(nullptr, value.c_str() + 1, &pabyData, nullptr,
2✔
243
                          1024 * 1024))
2✔
244
        {
245
            // Remove UTF-8 BOM
246
            size_t offset = 0;
1✔
247
            if (pabyData[0] == 0xEF && pabyData[1] == 0xBB &&
1✔
248
                pabyData[2] == 0xBF)
1✔
249
            {
250
                offset = 3;
1✔
251
            }
252
            value = reinterpret_cast<const char *>(pabyData + offset);
1✔
253
            VSIFree(pabyData);
1✔
254
        }
255
        else
256
        {
257
            return false;
1✔
258
        }
259
    }
260

261
    if (m_decl.IsRemoveSQLCommentsEnabled())
259✔
262
        value = CPLRemoveSQLComments(value);
20✔
263

264
    return true;
259✔
265
}
266

267
bool GDALAlgorithmArg::Set(const std::string &value)
250✔
268
{
269
    if (m_decl.GetType() != GAAT_STRING)
250✔
270
    {
271
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
272
                 "Calling Set(std::string) on argument '%s' of type %s is not "
273
                 "supported",
274
                 GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
1✔
275
        return false;
1✔
276
    }
277

278
    std::string newValue(value);
249✔
279
    return ProcessString(newValue) && SetInternal(newValue);
249✔
280
}
281

282
bool GDALAlgorithmArg::Set(int value)
22✔
283
{
284
    if (m_decl.GetType() == GAAT_REAL)
22✔
285
    {
286
        return Set(static_cast<double>(value));
2✔
287
    }
288
    if (m_decl.GetType() != GAAT_INTEGER)
20✔
289
    {
290
        CPLError(
2✔
291
            CE_Failure, CPLE_AppDefined,
292
            "Calling Set(int) on argument '%s' of type %s is not supported",
293
            GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
1✔
294
        return false;
1✔
295
    }
296
    return SetInternal(value);
19✔
297
}
298

299
bool GDALAlgorithmArg::Set(double value)
14✔
300
{
301
    if (m_decl.GetType() != GAAT_REAL)
14✔
302
    {
303
        CPLError(
2✔
304
            CE_Failure, CPLE_AppDefined,
305
            "Calling Set(double) on argument '%s' of type %s is not supported",
306
            GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
1✔
307
        return false;
1✔
308
    }
309
    return SetInternal(value);
13✔
310
}
311

312
bool GDALAlgorithmArg::Set(GDALDataset *ds)
16✔
313
{
314
    if (m_decl.GetType() != GAAT_DATASET)
16✔
315
    {
316
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
317
                 "Calling Set(GDALDataset*, bool) on argument '%s' of type %s "
318
                 "is not supported",
319
                 GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
1✔
320
        return false;
1✔
321
    }
322
    auto &val = *std::get<GDALArgDatasetValue *>(m_value);
15✔
323
    if (val.GetInputFlags() == GADV_NAME && val.GetOutputFlags() == GADV_OBJECT)
15✔
324
    {
325
        CPLError(
2✔
326
            CE_Failure, CPLE_AppDefined,
327
            "Dataset object '%s' is created by algorithm and cannot be set "
328
            "as an input.",
329
            GetName().c_str());
2✔
330
        return false;
2✔
331
    }
332
    m_explicitlySet = true;
13✔
333
    val.Set(ds);
13✔
334
    return RunAllActions();
13✔
335
}
336

337
bool GDALAlgorithmArg::Set(std::unique_ptr<GDALDataset> ds)
2✔
338
{
339
    if (m_decl.GetType() != GAAT_DATASET)
2✔
340
    {
341
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
342
                 "Calling Set(GDALDataset*, bool) on argument '%s' of type %s "
343
                 "is not supported",
344
                 GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
1✔
345
        return false;
1✔
346
    }
347
    auto &val = *std::get<GDALArgDatasetValue *>(m_value);
1✔
348
    if (val.GetInputFlags() == GADV_NAME && val.GetOutputFlags() == GADV_OBJECT)
1✔
349
    {
350
        CPLError(
×
351
            CE_Failure, CPLE_AppDefined,
352
            "Dataset object '%s' is created by algorithm and cannot be set "
353
            "as an input.",
354
            GetName().c_str());
×
355
        return false;
×
356
    }
357
    m_explicitlySet = true;
1✔
358
    val.Set(std::move(ds));
1✔
359
    return RunAllActions();
1✔
360
}
361

362
bool GDALAlgorithmArg::SetDatasetName(const std::string &name)
404✔
363
{
364
    if (m_decl.GetType() != GAAT_DATASET)
404✔
365
    {
366
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
367
                 "Calling SetDatasetName() on argument '%s' of type %s is "
368
                 "not supported",
369
                 GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
1✔
370
        return false;
1✔
371
    }
372
    m_explicitlySet = true;
403✔
373
    std::get<GDALArgDatasetValue *>(m_value)->Set(name);
403✔
374
    return RunAllActions();
403✔
375
}
376

377
bool GDALAlgorithmArg::SetFrom(const GDALArgDatasetValue &other)
133✔
378
{
379
    if (m_decl.GetType() != GAAT_DATASET)
133✔
380
    {
381
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
382
                 "Calling SetFrom() on argument '%s' of type %s is "
383
                 "not supported",
384
                 GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
1✔
385
        return false;
1✔
386
    }
387
    m_explicitlySet = true;
132✔
388
    std::get<GDALArgDatasetValue *>(m_value)->SetFrom(other);
132✔
389
    return RunAllActions();
132✔
390
}
391

392
bool GDALAlgorithmArg::Set(const std::vector<std::string> &value)
149✔
393
{
394
    if (m_decl.GetType() != GAAT_STRING_LIST)
149✔
395
    {
396
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
397
                 "Calling Set(const std::vector<std::string> &) on argument "
398
                 "'%s' of type %s is not supported",
399
                 GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
1✔
400
        return false;
1✔
401
    }
402

403
    if (m_decl.IsReadFromFileAtSyntaxAllowed() ||
288✔
404
        m_decl.IsRemoveSQLCommentsEnabled())
140✔
405
    {
406
        std::vector<std::string> newValue(value);
16✔
407
        for (auto &s : newValue)
19✔
408
        {
409
            if (!ProcessString(s))
11✔
410
                return false;
×
411
        }
412
        return SetInternal(newValue);
8✔
413
    }
414
    else
415
    {
416
        return SetInternal(value);
140✔
417
    }
418
}
419

420
bool GDALAlgorithmArg::Set(const std::vector<int> &value)
38✔
421
{
422
    if (m_decl.GetType() != GAAT_INTEGER_LIST)
38✔
423
    {
424
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
425
                 "Calling Set(const std::vector<int> &) on argument '%s' of "
426
                 "type %s is not supported",
427
                 GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
1✔
428
        return false;
1✔
429
    }
430
    return SetInternal(value);
37✔
431
}
432

433
bool GDALAlgorithmArg::Set(const std::vector<double> &value)
74✔
434
{
435
    if (m_decl.GetType() != GAAT_REAL_LIST)
74✔
436
    {
437
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
438
                 "Calling Set(const std::vector<double> &) on argument '%s' of "
439
                 "type %s is not supported",
440
                 GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
1✔
441
        return false;
1✔
442
    }
443
    return SetInternal(value);
73✔
444
}
445

446
bool GDALAlgorithmArg::Set(std::vector<GDALArgDatasetValue> &&value)
31✔
447
{
448
    if (m_decl.GetType() != GAAT_DATASET_LIST)
31✔
449
    {
450
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
451
                 "Calling Set(const std::vector<GDALArgDatasetValue> &&) on "
452
                 "argument '%s' of type %s is not supported",
453
                 GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()));
1✔
454
        return false;
1✔
455
    }
456
    m_explicitlySet = true;
30✔
457
    *std::get<std::vector<GDALArgDatasetValue> *>(m_value) = std::move(value);
30✔
458
    return RunAllActions();
30✔
459
}
460

461
bool GDALAlgorithmArg::SetFrom(const GDALAlgorithmArg &other)
175✔
462
{
463
    if (m_decl.GetType() != other.GetType())
175✔
464
    {
465
        CPLError(CE_Failure, CPLE_AppDefined,
8✔
466
                 "Calling SetFrom() on argument '%s' of type %s whereas "
467
                 "other argument type is %s is not supported",
468
                 GetName().c_str(), GDALAlgorithmArgTypeName(m_decl.GetType()),
4✔
469
                 GDALAlgorithmArgTypeName(other.GetType()));
470
        return false;
4✔
471
    }
472

473
    switch (m_decl.GetType())
171✔
474
    {
475
        case GAAT_BOOLEAN:
5✔
476
            *std::get<bool *>(m_value) = *std::get<bool *>(other.m_value);
5✔
477
            break;
5✔
478
        case GAAT_STRING:
32✔
479
            *std::get<std::string *>(m_value) =
64✔
480
                *std::get<std::string *>(other.m_value);
32✔
481
            break;
32✔
482
        case GAAT_INTEGER:
1✔
483
            *std::get<int *>(m_value) = *std::get<int *>(other.m_value);
1✔
484
            break;
1✔
485
        case GAAT_REAL:
1✔
486
            *std::get<double *>(m_value) = *std::get<double *>(other.m_value);
1✔
487
            break;
1✔
488
        case GAAT_DATASET:
128✔
489
            return SetFrom(other.Get<GDALArgDatasetValue>());
128✔
490
        case GAAT_STRING_LIST:
1✔
491
            *std::get<std::vector<std::string> *>(m_value) =
2✔
492
                *std::get<std::vector<std::string> *>(other.m_value);
1✔
493
            break;
1✔
494
        case GAAT_INTEGER_LIST:
1✔
495
            *std::get<std::vector<int> *>(m_value) =
2✔
496
                *std::get<std::vector<int> *>(other.m_value);
1✔
497
            break;
1✔
498
        case GAAT_REAL_LIST:
1✔
499
            *std::get<std::vector<double> *>(m_value) =
2✔
500
                *std::get<std::vector<double> *>(other.m_value);
1✔
501
            break;
1✔
502
        case GAAT_DATASET_LIST:
1✔
503
        {
504
            std::get<std::vector<GDALArgDatasetValue> *>(m_value)->clear();
1✔
505
            for (const auto &val :
2✔
506
                 *std::get<std::vector<GDALArgDatasetValue> *>(other.m_value))
5✔
507
            {
508
                GDALArgDatasetValue v;
4✔
509
                v.SetFrom(val);
2✔
510
                std::get<std::vector<GDALArgDatasetValue> *>(m_value)
2✔
511
                    ->push_back(std::move(v));
2✔
512
            }
513
            break;
1✔
514
        }
515
    }
516
    m_explicitlySet = true;
43✔
517
    return RunAllActions();
43✔
518
}
519

520
/************************************************************************/
521
/*                  GDALAlgorithmArg::RunAllActions()                   */
522
/************************************************************************/
523

524
bool GDALAlgorithmArg::RunAllActions()
1,306✔
525
{
526
    if (!RunValidationActions())
1,306✔
527
        return false;
26✔
528
    RunActions();
1,280✔
529
    return true;
1,280✔
530
}
531

532
/************************************************************************/
533
/*                      GDALAlgorithmArg::RunActions()                  */
534
/************************************************************************/
535

536
void GDALAlgorithmArg::RunActions()
1,281✔
537
{
538
    for (const auto &f : m_actions)
1,292✔
539
        f();
11✔
540
}
1,281✔
541

542
/************************************************************************/
543
/*                    GDALAlgorithmArg::RunValidationActions()          */
544
/************************************************************************/
545

546
bool GDALAlgorithmArg::RunValidationActions()
1,306✔
547
{
548
    for (const auto &f : m_validationActions)
1,486✔
549
    {
550
        if (!f())
206✔
551
            return false;
26✔
552
    }
553
    return true;
1,280✔
554
}
555

556
/************************************************************************/
557
/*              GDALInConstructionAlgorithmArg::AddAlias()              */
558
/************************************************************************/
559

560
GDALInConstructionAlgorithmArg &
561
GDALInConstructionAlgorithmArg::AddAlias(const std::string &alias)
3,548✔
562
{
563
    m_decl.AddAlias(alias);
3,548✔
564
    if (m_owner)
3,548✔
565
        m_owner->AddAliasFor(this, alias);
3,548✔
566
    return *this;
3,548✔
567
}
568

569
/************************************************************************/
570
/*            GDALInConstructionAlgorithmArg::AddHiddenAlias()          */
571
/************************************************************************/
572

573
GDALInConstructionAlgorithmArg &
574
GDALInConstructionAlgorithmArg::AddHiddenAlias(const std::string &alias)
602✔
575
{
576
    m_decl.AddHiddenAlias(alias);
602✔
577
    if (m_owner)
602✔
578
        m_owner->AddAliasFor(this, alias);
602✔
579
    return *this;
602✔
580
}
581

582
/************************************************************************/
583
/*             GDALInConstructionAlgorithmArg::SetPositional()          */
584
/************************************************************************/
585

586
GDALInConstructionAlgorithmArg &GDALInConstructionAlgorithmArg::SetPositional()
1,133✔
587
{
588
    m_decl.SetPositional();
1,133✔
589
    if (m_owner)
1,133✔
590
        m_owner->SetPositional(this);
1,133✔
591
    return *this;
1,133✔
592
}
593

594
/************************************************************************/
595
/*              GDALArgDatasetValue::GDALArgDatasetValue()              */
596
/************************************************************************/
597

598
GDALArgDatasetValue::GDALArgDatasetValue(GDALDataset *poDS)
19✔
599
    : m_poDS(poDS), m_name(m_poDS ? m_poDS->GetDescription() : std::string()),
38✔
600
      m_nameSet(true)
19✔
601
{
602
    if (m_poDS)
19✔
603
        m_poDS->Reference();
19✔
604
}
19✔
605

606
/************************************************************************/
607
/*              GDALArgDatasetValue::Set()                              */
608
/************************************************************************/
609

610
void GDALArgDatasetValue::Set(const std::string &name)
463✔
611
{
612
    Close();
463✔
613
    m_name = name;
463✔
614
    m_nameSet = true;
463✔
615
    if (m_ownerArg)
463✔
616
        m_ownerArg->NotifyValueSet();
459✔
617
}
463✔
618

619
/************************************************************************/
620
/*              GDALArgDatasetValue::Set()                              */
621
/************************************************************************/
622

623
void GDALArgDatasetValue::Set(std::unique_ptr<GDALDataset> poDS)
235✔
624
{
625
    Close();
235✔
626
    m_poDS = poDS.release();
235✔
627
    m_name = m_poDS ? m_poDS->GetDescription() : std::string();
235✔
628
    m_nameSet = true;
235✔
629
    if (m_ownerArg)
235✔
630
        m_ownerArg->NotifyValueSet();
217✔
631
}
235✔
632

633
/************************************************************************/
634
/*              GDALArgDatasetValue::Set()                              */
635
/************************************************************************/
636

637
void GDALArgDatasetValue::Set(GDALDataset *poDS)
726✔
638
{
639
    Close();
726✔
640
    m_poDS = poDS;
726✔
641
    if (m_poDS)
726✔
642
        m_poDS->Reference();
664✔
643
    m_name = m_poDS ? m_poDS->GetDescription() : std::string();
726✔
644
    m_nameSet = true;
726✔
645
    if (m_ownerArg)
726✔
646
        m_ownerArg->NotifyValueSet();
498✔
647
}
726✔
648

649
/************************************************************************/
650
/*                   GDALArgDatasetValue::SetFrom()                     */
651
/************************************************************************/
652

653
void GDALArgDatasetValue::SetFrom(const GDALArgDatasetValue &other)
134✔
654
{
655
    Close();
134✔
656
    m_name = other.m_name;
134✔
657
    m_nameSet = other.m_nameSet;
134✔
658
    m_poDS = other.m_poDS;
134✔
659
    if (m_poDS)
134✔
660
        m_poDS->Reference();
67✔
661
}
134✔
662

663
/************************************************************************/
664
/*              GDALArgDatasetValue::~GDALArgDatasetValue()             */
665
/************************************************************************/
666

667
GDALArgDatasetValue::~GDALArgDatasetValue()
1,971✔
668
{
669
    Close();
1,971✔
670
}
1,971✔
671

672
/************************************************************************/
673
/*                     GDALArgDatasetValue::Close()                     */
674
/************************************************************************/
675

676
bool GDALArgDatasetValue::Close()
3,917✔
677
{
678
    bool ret = true;
3,917✔
679
    if (m_poDS && m_poDS->Dereference() == 0)
3,917✔
680
    {
681
        ret = m_poDS->Close() == CE_None;
458✔
682
        delete m_poDS;
458✔
683
    }
684
    m_poDS = nullptr;
3,917✔
685
    return ret;
3,917✔
686
}
687

688
/************************************************************************/
689
/*                      GDALArgDatasetValue::operator=()                */
690
/************************************************************************/
691

692
GDALArgDatasetValue &GDALArgDatasetValue::operator=(GDALArgDatasetValue &&other)
2✔
693
{
694
    Close();
2✔
695
    m_poDS = other.m_poDS;
2✔
696
    m_name = other.m_name;
2✔
697
    m_nameSet = other.m_nameSet;
2✔
698
    m_type = other.m_type;
2✔
699
    m_inputFlags = other.m_inputFlags;
2✔
700
    m_outputFlags = other.m_outputFlags;
2✔
701
    other.m_poDS = nullptr;
2✔
702
    other.m_name.clear();
2✔
703
    other.m_nameSet = false;
2✔
704
    return *this;
2✔
705
}
706

707
/************************************************************************/
708
/*                   GDALArgDatasetValue::GetDataset()                  */
709
/************************************************************************/
710

711
GDALDataset *GDALArgDatasetValue::GetDatasetIncreaseRefCount()
45✔
712
{
713
    if (m_poDS)
45✔
714
        m_poDS->Reference();
44✔
715
    return m_poDS;
45✔
716
}
717

718
/************************************************************************/
719
/*               GDALArgDatasetValue(GDALArgDatasetValue &&other)       */
720
/************************************************************************/
721

722
GDALArgDatasetValue::GDALArgDatasetValue(GDALArgDatasetValue &&other)
27✔
723
    : m_poDS(other.m_poDS), m_name(other.m_name), m_nameSet(other.m_nameSet),
54✔
724
      m_type(other.m_type), m_inputFlags(other.m_inputFlags),
27✔
725
      m_outputFlags(other.m_outputFlags)
27✔
726
{
727
    other.m_poDS = nullptr;
27✔
728
    other.m_name.clear();
27✔
729
}
27✔
730

731
/************************************************************************/
732
/*              GDALInConstructionAlgorithmArg::SetIsCRSArg()           */
733
/************************************************************************/
734

735
GDALInConstructionAlgorithmArg &
736
GDALInConstructionAlgorithmArg::SetIsCRSArg(bool noneAllowed)
258✔
737
{
738
    if (GetType() != GAAT_STRING)
258✔
739
    {
740
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
741
                 "SetIsCRSArg() can only be called on a String argument");
742
        return *this;
1✔
743
    }
744
    AddValidationAction(
745
        [this, noneAllowed]()
65✔
746
        {
747
            const std::string &osVal =
748
                static_cast<const GDALInConstructionAlgorithmArg *>(this)
749
                    ->Get<std::string>();
30✔
750
            if (!noneAllowed || (osVal != "none" && osVal != "null"))
30✔
751
            {
752
                OGRSpatialReference oSRS;
27✔
753
                if (oSRS.SetFromUserInput(osVal.c_str()) != OGRERR_NONE)
27✔
754
                {
755
                    m_owner->ReportError(CE_Failure, CPLE_AppDefined,
5✔
756
                                         "Invalid value for '%s' argument",
757
                                         GetName().c_str());
5✔
758
                    return false;
5✔
759
                }
760
            }
761
            return true;
25✔
762
        });
257✔
763

764
    SetAutoCompleteFunction(
765
        [](const std::string &currentValue)
6✔
766
        {
767
            std::vector<std::string> oRet;
6✔
768
            if (!currentValue.empty())
6✔
769
            {
770
                const CPLStringList aosTokens(
771
                    CSLTokenizeString2(currentValue.c_str(), ":", 0));
10✔
772
                int nCount = 0;
5✔
773
                OSRCRSInfo **pCRSList = OSRGetCRSInfoListFromDatabase(
5✔
774
                    aosTokens[0], nullptr, &nCount);
775
                std::string osCode;
10✔
776
                for (int i = 0; i < nCount; ++i)
33,050✔
777
                {
778
                    if (aosTokens.size() == 1 ||
52,872✔
779
                        STARTS_WITH(pCRSList[i]->pszCode, aosTokens[1]))
19,827✔
780
                    {
781
                        if (oRet.empty())
13,409✔
782
                            osCode = pCRSList[i]->pszCode;
5✔
783
                        oRet.push_back(std::string(pCRSList[i]->pszCode)
26,818✔
784
                                           .append(" -- ")
13,409✔
785
                                           .append(pCRSList[i]->pszName));
13,409✔
786
                    }
787
                }
788
                if (oRet.size() == 1)
5✔
789
                {
790
                    // If there is a single match, remove the name from the suggestion.
791
                    oRet.clear();
1✔
792
                    oRet.push_back(osCode);
1✔
793
                }
794
                OSRDestroyCRSInfoList(pCRSList);
5✔
795
            }
796
            if (oRet.empty())
6✔
797
            {
798
                const CPLStringList aosAuthorities(
799
                    OSRGetAuthorityListFromDatabase());
2✔
800
                for (const char *pszAuth : cpl::Iterate(aosAuthorities))
6✔
801
                {
802
                    int nCount = 0;
5✔
803
                    OSRCRSInfo **pCRSList = OSRGetCRSInfoListFromDatabase(
5✔
804
                        pszAuth, nullptr, &nCount);
805
                    OSRDestroyCRSInfoList(pCRSList);
5✔
806
                    if (nCount)
5✔
807
                        oRet.push_back(std::string(pszAuth).append(":"));
4✔
808
                }
809
            }
810
            return oRet;
6✔
811
        });
257✔
812

813
    return *this;
257✔
814
}
815

816
/************************************************************************/
817
/*                     GDALAlgorithm::GDALAlgorithm()                  */
818
/************************************************************************/
819

820
GDALAlgorithm::GDALAlgorithm(const std::string &name,
1,517✔
821
                             const std::string &description,
822
                             const std::string &helpURL)
1,517✔
823
    : m_name(name), m_description(description), m_helpURL(helpURL),
824
      m_helpFullURL(!m_helpURL.empty() && m_helpURL[0] == '/'
3,034✔
825
                        ? "https://gdal.org" + m_helpURL
1,517✔
826
                        : m_helpURL)
4,404✔
827
{
828
    AddArg("help", 'h', _("Display help message and exit"), &m_helpRequested)
3,034✔
829
        .SetOnlyForCLI()
1,517✔
830
        .SetCategory(GAAC_COMMON)
3,034✔
831
        .AddAction([this]() { m_specialActionRequested = true; });
1,517✔
832
    AddArg("version", 0, _("Display GDAL version and exit"), &m_dummyBoolean)
3,034✔
833
        .SetOnlyForCLI()
1,517✔
834
        .SetCategory(GAAC_COMMON);
1,517✔
835
    AddArg("json-usage", 0, _("Display usage as JSON document and exit"),
836
           &m_JSONUsageRequested)
3,034✔
837
        .SetOnlyForCLI()
1,517✔
838
        .SetCategory(GAAC_COMMON)
3,034✔
839
        .AddAction([this]() { m_specialActionRequested = true; });
1,517✔
840
    AddArg("drivers", 0, _("Display driver list as JSON document and exit"),
841
           &m_dummyBoolean)
3,034✔
842
        .SetOnlyForCLI()
1,517✔
843
        .SetCategory(GAAC_COMMON);
1,517✔
844
    AddArg("config", 0, _("Configuration option"), &m_dummyConfigOptions)
3,034✔
845
        .SetMetaVar("<KEY>=<VALUE>")
3,034✔
846
        .SetOnlyForCLI()
1,517✔
847
        .SetCategory(GAAC_COMMON);
1,517✔
848
}
1,517✔
849

850
/************************************************************************/
851
/*                     GDALAlgorithm::~GDALAlgorithm()                  */
852
/************************************************************************/
853

854
GDALAlgorithm::~GDALAlgorithm() = default;
855

856
/************************************************************************/
857
/*                    GDALAlgorithm::ParseArgument()                    */
858
/************************************************************************/
859

860
bool GDALAlgorithm::ParseArgument(
995✔
861
    GDALAlgorithmArg *arg, const std::string &name, const std::string &value,
862
    std::map<
863
        GDALAlgorithmArg *,
864
        std::variant<std::vector<std::string>, std::vector<int>,
865
                     std::vector<double>, std::vector<GDALArgDatasetValue>>>
866
        &inConstructionValues)
867
{
868
    const bool isListArg = GDALAlgorithmArgTypeIsList(arg->GetType());
995✔
869
    if (arg->IsExplicitlySet() && !isListArg)
995✔
870
    {
871
        // Hack for "gdal info" to be able to pass an opened raster dataset
872
        // by "gdal raster info" to the "gdal vector info" algorithm.
873
        if (arg->SkipIfAlreadySet())
3✔
874
        {
875
            arg->SetSkipIfAlreadySet(false);
1✔
876
            return true;
1✔
877
        }
878

879
        ReportError(CE_Failure, CPLE_IllegalArg,
2✔
880
                    "Argument '%s' has already been specified.", name.c_str());
881
        return false;
2✔
882
    }
883

884
    if (!arg->GetRepeatedArgAllowed() &&
1,034✔
885
        cpl::contains(inConstructionValues, arg))
42✔
886
    {
887
        ReportError(CE_Failure, CPLE_IllegalArg,
1✔
888
                    "Argument '%s' has already been specified.", name.c_str());
889
        return false;
1✔
890
    }
891

892
    switch (arg->GetType())
991✔
893
    {
894
        case GAAT_BOOLEAN:
133✔
895
        {
896
            if (value.empty() || value == "true")
133✔
897
                return arg->Set(true);
131✔
898
            else if (value == "false")
2✔
899
                return arg->Set(false);
1✔
900
            else
901
            {
902
                ReportError(
1✔
903
                    CE_Failure, CPLE_IllegalArg,
904
                    "Invalid value '%s' for boolean argument '%s'. Should be "
905
                    "'true' or 'false'.",
906
                    value.c_str(), name.c_str());
907
                return false;
1✔
908
            }
909
        }
910

911
        case GAAT_STRING:
215✔
912
        {
913
            const auto &choices = arg->GetChoices();
215✔
914
            const auto &hiddenChoices = arg->GetHiddenChoices();
215✔
915
            if (!choices.empty() &&
245✔
916
                std::find(choices.begin(), choices.end(), value) ==
30✔
917
                    choices.end() &&
245✔
918
                std::find(hiddenChoices.begin(), hiddenChoices.end(), value) ==
3✔
919
                    hiddenChoices.end())
218✔
920
            {
921
                std::string expected;
2✔
922
                for (const auto &choice : choices)
7✔
923
                {
924
                    if (!expected.empty())
5✔
925
                        expected += ", ";
3✔
926
                    expected += '\'';
5✔
927
                    expected += choice;
5✔
928
                    expected += '\'';
5✔
929
                }
930
                ReportError(
2✔
931
                    CE_Failure, CPLE_IllegalArg,
932
                    "Invalid value '%s' for string argument '%s'. Should be "
933
                    "one among %s.",
934
                    value.c_str(), name.c_str(), expected.c_str());
935
                return false;
2✔
936
            }
937

938
            return arg->Set(value);
213✔
939
        }
940

941
        case GAAT_INTEGER:
11✔
942
        {
943
            errno = 0;
11✔
944
            char *endptr = nullptr;
11✔
945
            const auto val = std::strtol(value.c_str(), &endptr, 10);
11✔
946
            if (errno == 0 && endptr &&
10✔
947
                endptr == value.c_str() + value.size() && val >= INT_MIN &&
21✔
948
                val <= INT_MAX)
949
            {
950
                return arg->Set(static_cast<int>(val));
8✔
951
            }
952
            else
953
            {
954
                ReportError(CE_Failure, CPLE_IllegalArg,
3✔
955
                            "Expected integer value for argument '%s', "
956
                            "but got '%s'.",
957
                            name.c_str(), value.c_str());
958
                return false;
3✔
959
            }
960
        }
961

962
        case GAAT_REAL:
10✔
963
        {
964
            char *endptr = nullptr;
10✔
965
            double dfValue = CPLStrtod(value.c_str(), &endptr);
10✔
966
            if (endptr != value.c_str() + value.size())
10✔
967
            {
968
                ReportError(
1✔
969
                    CE_Failure, CPLE_IllegalArg,
970
                    "Expected real value for argument '%s', but got '%s'.",
971
                    name.c_str(), value.c_str());
972
                return false;
1✔
973
            }
974
            return arg->Set(dfValue);
9✔
975
        }
976

977
        case GAAT_DATASET:
402✔
978
        {
979
            return arg->SetDatasetName(value);
402✔
980
        }
981

982
        case GAAT_STRING_LIST:
101✔
983
        {
984
            const CPLStringList aosTokens(
985
                arg->GetPackedValuesAllowed()
101✔
986
                    ? CSLTokenizeString2(value.c_str(), ",", CSLT_HONOURSTRINGS)
87✔
987
                    : CSLAddString(nullptr, value.c_str()));
188✔
988
            if (!cpl::contains(inConstructionValues, arg))
101✔
989
            {
990
                inConstructionValues[arg] = std::vector<std::string>();
77✔
991
            }
992
            auto &valueVector =
993
                std::get<std::vector<std::string>>(inConstructionValues[arg]);
101✔
994
            const auto &choices = arg->GetChoices();
101✔
995
            const auto &hiddenChoices = arg->GetHiddenChoices();
101✔
996
            for (const char *v : aosTokens)
219✔
997
            {
998
                if (!choices.empty() &&
132✔
999
                    std::find(choices.begin(), choices.end(), v) ==
10✔
1000
                        choices.end() &&
132✔
1001
                    std::find(hiddenChoices.begin(), hiddenChoices.end(),
×
1002
                              value) == hiddenChoices.end())
126✔
1003
                {
1004
                    std::string expected;
4✔
1005
                    for (const auto &choice : choices)
10✔
1006
                    {
1007
                        if (!expected.empty())
6✔
1008
                            expected += ", ";
2✔
1009
                        expected += '\'';
6✔
1010
                        expected += choice;
6✔
1011
                        expected += '\'';
6✔
1012
                    }
1013
                    ReportError(CE_Failure, CPLE_IllegalArg,
4✔
1014
                                "Invalid value '%s' for string argument '%s'. "
1015
                                "Should be "
1016
                                "one among %s.",
1017
                                v, name.c_str(), expected.c_str());
1018
                    return false;
4✔
1019
                }
1020

1021
                valueVector.push_back(v);
118✔
1022
            }
1023
            break;
97✔
1024
        }
1025

1026
        case GAAT_INTEGER_LIST:
39✔
1027
        {
1028
            const CPLStringList aosTokens(
1029
                arg->GetPackedValuesAllowed()
39✔
1030
                    ? CSLTokenizeString2(value.c_str(), ",", CSLT_HONOURSTRINGS)
39✔
1031
                    : CSLAddString(nullptr, value.c_str()));
78✔
1032
            if (!cpl::contains(inConstructionValues, arg))
39✔
1033
            {
1034
                inConstructionValues[arg] = std::vector<int>();
35✔
1035
            }
1036
            auto &valueVector =
1037
                std::get<std::vector<int>>(inConstructionValues[arg]);
39✔
1038
            for (const char *v : aosTokens)
123✔
1039
            {
1040
                errno = 0;
88✔
1041
                char *endptr = nullptr;
88✔
1042
                const auto val = std::strtol(v, &endptr, 10);
88✔
1043
                if (errno == 0 && endptr && endptr == v + strlen(v) &&
88✔
1044
                    val >= INT_MIN && val <= INT_MAX)
84✔
1045
                {
1046
                    valueVector.push_back(static_cast<int>(val));
84✔
1047
                }
1048
                else
1049
                {
1050
                    ReportError(
4✔
1051
                        CE_Failure, CPLE_IllegalArg,
1052
                        "Expected list of integer value for argument '%s', "
1053
                        "but got '%s'.",
1054
                        name.c_str(), value.c_str());
1055
                    return false;
4✔
1056
                }
1057
            }
1058
            break;
35✔
1059
        }
1060

1061
        case GAAT_REAL_LIST:
68✔
1062
        {
1063
            const CPLStringList aosTokens(
1064
                arg->GetPackedValuesAllowed()
68✔
1065
                    ? CSLTokenizeString2(value.c_str(), ",", CSLT_HONOURSTRINGS)
68✔
1066
                    : CSLAddString(nullptr, value.c_str()));
136✔
1067
            if (!cpl::contains(inConstructionValues, arg))
68✔
1068
            {
1069
                inConstructionValues[arg] = std::vector<double>();
66✔
1070
            }
1071
            auto &valueVector =
1072
                std::get<std::vector<double>>(inConstructionValues[arg]);
68✔
1073
            for (const char *v : aosTokens)
275✔
1074
            {
1075
                char *endptr = nullptr;
209✔
1076
                double dfValue = CPLStrtod(v, &endptr);
209✔
1077
                if (endptr != v + strlen(v))
209✔
1078
                {
1079
                    ReportError(
2✔
1080
                        CE_Failure, CPLE_IllegalArg,
1081
                        "Expected list of real value for argument '%s', "
1082
                        "but got '%s'.",
1083
                        name.c_str(), value.c_str());
1084
                    return false;
2✔
1085
                }
1086
                valueVector.push_back(dfValue);
207✔
1087
            }
1088
            break;
66✔
1089
        }
1090

1091
        case GAAT_DATASET_LIST:
12✔
1092
        {
1093
            const CPLStringList aosTokens(
1094
                CSLTokenizeString2(value.c_str(), ",", CSLT_HONOURSTRINGS));
24✔
1095
            if (!cpl::contains(inConstructionValues, arg))
12✔
1096
            {
1097
                inConstructionValues[arg] = std::vector<GDALArgDatasetValue>();
11✔
1098
            }
1099
            auto &valueVector = std::get<std::vector<GDALArgDatasetValue>>(
1100
                inConstructionValues[arg]);
12✔
1101
            for (const char *v : aosTokens)
24✔
1102
            {
1103
                valueVector.push_back(GDALArgDatasetValue(v));
12✔
1104
            }
1105
            break;
12✔
1106
        }
1107
    }
1108

1109
    return true;
210✔
1110
}
1111

1112
/************************************************************************/
1113
/*               GDALAlgorithm::ParseCommandLineArguments()             */
1114
/************************************************************************/
1115

1116
bool GDALAlgorithm::ParseCommandLineArguments(
532✔
1117
    const std::vector<std::string> &args)
1118
{
1119
    if (m_parsedSubStringAlreadyCalled)
532✔
1120
    {
1121
        ReportError(CE_Failure, CPLE_AppDefined,
1✔
1122
                    "ParseCommandLineArguments() can only be called once per "
1123
                    "instance.");
1124
        return false;
1✔
1125
    }
1126
    m_parsedSubStringAlreadyCalled = true;
531✔
1127

1128
    // AWS like syntax supported too (not advertized)
1129
    if (args.size() == 1 && args[0] == "help")
531✔
1130
    {
1131
        auto arg = GetArg("help");
1✔
1132
        assert(arg);
1✔
1133
        arg->Set(true);
1✔
1134
        arg->RunActions();
1✔
1135
        return true;
1✔
1136
    }
1137

1138
    if (HasSubAlgorithms())
530✔
1139
    {
1140
        if (args.empty())
29✔
1141
        {
1142
            ReportError(CE_Failure, CPLE_AppDefined, "Missing %s name.",
2✔
1143
                        m_callPath.size() == 1 ? "command" : "subcommand");
2✔
1144
            return false;
2✔
1145
        }
1146
        if (!args[0].empty() && args[0][0] == '-')
27✔
1147
        {
1148
            // go on argument parsing
1149
        }
1150
        else
1151
        {
1152
            m_shortCutAlg = InstantiateSubAlgorithm(args[0]);
24✔
1153
            if (m_shortCutAlg)
24✔
1154
            {
1155
                m_selectedSubAlg = m_shortCutAlg.get();
23✔
1156
                bool bRet = m_selectedSubAlg->ParseCommandLineArguments(
23✔
1157
                    std::vector<std::string>(args.begin() + 1, args.end()));
46✔
1158
                m_selectedSubAlg->PropagateSpecialActionTo(this);
23✔
1159
                return bRet;
23✔
1160
            }
1161
            else
1162
            {
1163
                ReportError(CE_Failure, CPLE_AppDefined,
1✔
1164
                            "Unknown command: '%s'", args[0].c_str());
1✔
1165
                return false;
1✔
1166
            }
1167
        }
1168
    }
1169

1170
    std::map<
1171
        GDALAlgorithmArg *,
1172
        std::variant<std::vector<std::string>, std::vector<int>,
1173
                     std::vector<double>, std::vector<GDALArgDatasetValue>>>
1174
        inConstructionValues;
1,008✔
1175

1176
    std::vector<std::string> lArgs(args);
1,008✔
1177
    for (size_t i = 0; i < lArgs.size(); /* incremented in loop */)
1,492✔
1178
    {
1179
        const auto &strArg = lArgs[i];
1,042✔
1180
        GDALAlgorithmArg *arg = nullptr;
1,042✔
1181
        std::string name;
1,042✔
1182
        std::string value;
1,042✔
1183
        bool hasValue = false;
1,042✔
1184
        if (strArg.size() >= 2 && strArg[0] == '-' && strArg[1] == '-')
1,042✔
1185
        {
1186
            const auto equalPos = strArg.find('=');
549✔
1187
            name = (equalPos != std::string::npos) ? strArg.substr(0, equalPos)
1,098✔
1188
                                                   : strArg;
549✔
1189
            auto iterArg = m_mapLongNameToArg.find(name.substr(2));
549✔
1190
            if (iterArg == m_mapLongNameToArg.end())
549✔
1191
            {
1192
                ReportError(CE_Failure, CPLE_IllegalArg,
16✔
1193
                            "Long name option '%s' is unknown.", name.c_str());
1194
                return false;
16✔
1195
            }
1196
            arg = iterArg->second;
533✔
1197
            if (equalPos != std::string::npos)
533✔
1198
            {
1199
                hasValue = true;
169✔
1200
                value = strArg.substr(equalPos + 1);
169✔
1201
            }
1202
        }
1203
        else if (strArg.size() >= 2 && strArg[0] == '-')
493✔
1204
        {
1205
            if (strArg.size() != 2)
59✔
1206
            {
1207
                ReportError(
1✔
1208
                    CE_Failure, CPLE_IllegalArg,
1209
                    "Option '%s' not recognized. Should be either a long "
1210
                    "option or a one-letter short option.",
1211
                    strArg.c_str());
1212
                return false;
2✔
1213
            }
1214
            name = strArg;
58✔
1215
            auto iterArg = m_mapShortNameToArg.find(name.substr(1));
58✔
1216
            if (iterArg == m_mapShortNameToArg.end())
58✔
1217
            {
1218
                ReportError(CE_Failure, CPLE_IllegalArg,
1✔
1219
                            "Short name option '%s' is unknown.", name.c_str());
1220
                return false;
1✔
1221
            }
1222
            arg = iterArg->second;
57✔
1223
        }
1224
        else
1225
        {
1226
            ++i;
434✔
1227
            continue;
434✔
1228
        }
1229
        assert(arg);
590✔
1230

1231
        if (arg->GetType() == GAAT_BOOLEAN)
590✔
1232
        {
1233
            if (!hasValue)
134✔
1234
            {
1235
                hasValue = true;
131✔
1236
                value = "true";
131✔
1237
            }
1238
        }
1239

1240
        if (!hasValue)
590✔
1241
        {
1242
            if (i + 1 == lArgs.size())
290✔
1243
            {
1244
                if (m_parseForAutoCompletion)
13✔
1245
                {
1246
                    lArgs.erase(lArgs.begin() + i);
12✔
1247
                    break;
12✔
1248
                }
1249
                ReportError(
1✔
1250
                    CE_Failure, CPLE_IllegalArg,
1251
                    "Expected value for argument '%s', but ran short of tokens",
1252
                    name.c_str());
1253
                return false;
1✔
1254
            }
1255
            value = lArgs[i + 1];
277✔
1256
            lArgs.erase(lArgs.begin() + i + 1);
277✔
1257
        }
1258

1259
        if (!ParseArgument(arg, name, value, inConstructionValues))
577✔
1260
            return false;
23✔
1261

1262
        lArgs.erase(lArgs.begin() + i);
554✔
1263
    }
1264

1265
    if (m_specialActionRequested)
462✔
1266
    {
1267
        return true;
8✔
1268
    }
1269

1270
    const auto ProcessInConstructionValues = [&inConstructionValues]()
633✔
1271
    {
1272
        for (auto &[arg, value] : inConstructionValues)
619✔
1273
        {
1274
            if (arg->GetType() == GAAT_STRING_LIST)
181✔
1275
            {
1276
                if (!arg->Set(std::get<std::vector<std::string>>(
74✔
1277
                        inConstructionValues[arg])))
74✔
1278
                {
1279
                    return false;
14✔
1280
                }
1281
            }
1282
            else if (arg->GetType() == GAAT_INTEGER_LIST)
107✔
1283
            {
1284
                if (!arg->Set(
32✔
1285
                        std::get<std::vector<int>>(inConstructionValues[arg])))
32✔
1286
                {
1287
                    return false;
1✔
1288
                }
1289
            }
1290
            else if (arg->GetType() == GAAT_REAL_LIST)
75✔
1291
            {
1292
                if (!arg->Set(std::get<std::vector<double>>(
64✔
1293
                        inConstructionValues[arg])))
64✔
1294
                {
1295
                    return false;
6✔
1296
                }
1297
            }
1298
            else if (arg->GetType() == GAAT_DATASET_LIST)
11✔
1299
            {
1300
                if (!arg->Set(
11✔
1301
                        std::move(std::get<std::vector<GDALArgDatasetValue>>(
1302
                            inConstructionValues[arg]))))
11✔
1303
                {
1304
                    return false;
1✔
1305
                }
1306
            }
1307
        }
1308
        return true;
438✔
1309
    };
454✔
1310

1311
    size_t i = 0;
454✔
1312
    size_t iCurPosArg = 0;
454✔
1313
    while (i < lArgs.size() && iCurPosArg < m_positionalArgs.size())
854✔
1314
    {
1315
        GDALAlgorithmArg *arg = m_positionalArgs[iCurPosArg];
409✔
1316
        while (arg->IsExplicitlySet())
412✔
1317
        {
1318
            ++iCurPosArg;
4✔
1319
            if (iCurPosArg == m_positionalArgs.size())
4✔
1320
                break;
1✔
1321
            arg = m_positionalArgs[iCurPosArg];
3✔
1322
        }
1323
        if (iCurPosArg == m_positionalArgs.size())
409✔
1324
        {
1325
            break;
1✔
1326
        }
1327
        if (GDALAlgorithmArgTypeIsList(arg->GetType()) &&
439✔
1328
            arg->GetMinCount() != arg->GetMaxCount())
31✔
1329
        {
1330
            if (iCurPosArg == 0)
26✔
1331
            {
1332
                size_t nCountAtEnd = 0;
15✔
1333
                for (size_t j = 1; j < m_positionalArgs.size(); j++)
27✔
1334
                {
1335
                    const auto *otherArg = m_positionalArgs[j];
14✔
1336
                    if (GDALAlgorithmArgTypeIsList(otherArg->GetType()))
14✔
1337
                    {
1338
                        if (otherArg->GetMinCount() != otherArg->GetMaxCount())
4✔
1339
                        {
1340
                            ReportError(
2✔
1341
                                CE_Failure, CPLE_AppDefined,
1342
                                "Ambiguity in definition of positional "
1343
                                "argument "
1344
                                "'%s' given it has a varying number of values, "
1345
                                "but follows argument '%s' which also has a "
1346
                                "varying number of values",
1347
                                otherArg->GetName().c_str(),
1✔
1348
                                arg->GetName().c_str());
1✔
1349
                            ProcessInConstructionValues();
1✔
1350
                            return false;
1✔
1351
                        }
1352
                        nCountAtEnd += otherArg->GetMinCount();
3✔
1353
                    }
1354
                    else
1355
                    {
1356
                        if (!otherArg->IsRequired())
10✔
1357
                        {
1358
                            ReportError(
2✔
1359
                                CE_Failure, CPLE_AppDefined,
1360
                                "Ambiguity in definition of positional "
1361
                                "argument "
1362
                                "'%s', given it is not required but follows "
1363
                                "argument '%s' which has a varying number of "
1364
                                "values",
1365
                                otherArg->GetName().c_str(),
1✔
1366
                                arg->GetName().c_str());
1✔
1367
                            ProcessInConstructionValues();
1✔
1368
                            return false;
1✔
1369
                        }
1370
                        nCountAtEnd++;
9✔
1371
                    }
1372
                }
1373
                if (lArgs.size() < nCountAtEnd)
13✔
1374
                {
1375
                    ReportError(CE_Failure, CPLE_AppDefined,
1✔
1376
                                "Not enough positional values.");
1377
                    ProcessInConstructionValues();
1✔
1378
                    return false;
1✔
1379
                }
1380
                for (; i < lArgs.size() - nCountAtEnd; ++i)
29✔
1381
                {
1382
                    if (!ParseArgument(arg, arg->GetName().c_str(), lArgs[i],
18✔
1383
                                       inConstructionValues))
1384
                    {
1385
                        ProcessInConstructionValues();
1✔
1386
                        return false;
1✔
1387
                    }
1388
                }
1389
            }
1390
            else if (iCurPosArg == m_positionalArgs.size() - 1)
11✔
1391
            {
1392
                for (; i < lArgs.size(); ++i)
24✔
1393
                {
1394
                    if (!ParseArgument(arg, arg->GetName().c_str(), lArgs[i],
15✔
1395
                                       inConstructionValues))
1396
                    {
1397
                        ProcessInConstructionValues();
1✔
1398
                        return false;
1✔
1399
                    }
1400
                }
1401
            }
1402
            else
1403
            {
1404
                ReportError(CE_Failure, CPLE_AppDefined,
1✔
1405
                            "Ambiguity in definition of positional arguments: "
1406
                            "arguments with varying number of values must be "
1407
                            "first or last one.");
1408
                return false;
1✔
1409
            }
1410
        }
1411
        else
1412
        {
1413
            if (lArgs.size() - i < static_cast<size_t>(arg->GetMaxCount()))
382✔
1414
            {
1415
                ReportError(CE_Failure, CPLE_AppDefined,
1✔
1416
                            "Not enough positional values.");
1417
                return false;
1✔
1418
            }
1419
            const size_t iMax = i + arg->GetMaxCount();
381✔
1420
            for (; i < iMax; ++i)
765✔
1421
            {
1422
                if (!ParseArgument(arg, arg->GetName().c_str(), lArgs[i],
385✔
1423
                                   inConstructionValues))
1424
                {
1425
                    ProcessInConstructionValues();
1✔
1426
                    return false;
1✔
1427
                }
1428
            }
1429
        }
1430
        ++iCurPosArg;
400✔
1431
    }
1432

1433
    if (i < lArgs.size())
446✔
1434
    {
1435
        ReportError(CE_Failure, CPLE_AppDefined,
3✔
1436
                    "Positional values starting at '%s' are not expected.",
1437
                    lArgs[i].c_str());
3✔
1438
        ProcessInConstructionValues();
3✔
1439
        return false;
3✔
1440
    }
1441
    if (iCurPosArg < m_positionalArgs.size() &&
545✔
1442
        (GDALAlgorithmArgTypeIsList(m_positionalArgs[iCurPosArg]->GetType())
102✔
1443
             ? m_positionalArgs[iCurPosArg]->GetMinCount() > 0
8✔
1444
             : m_positionalArgs[iCurPosArg]->IsRequired()))
94✔
1445
    {
1446
        while (iCurPosArg < m_positionalArgs.size() &&
274✔
1447
               m_positionalArgs[iCurPosArg]->IsExplicitlySet())
108✔
1448
        {
1449
            ++iCurPosArg;
86✔
1450
        }
1451
        if (iCurPosArg < m_positionalArgs.size())
80✔
1452
        {
1453
            ReportError(CE_Failure, CPLE_AppDefined,
22✔
1454
                        "Positional arguments starting at '%s' have not been "
1455
                        "specified.",
1456
                        m_positionalArgs[iCurPosArg]->GetMetaVar().c_str());
22✔
1457
            ProcessInConstructionValues();
22✔
1458
            return false;
22✔
1459
        }
1460
    }
1461

1462
    return ProcessInConstructionValues() &&
828✔
1463
           (m_skipValidationInParseCommandLine || ValidateArguments());
828✔
1464
}
1465

1466
/************************************************************************/
1467
/*                     GDALAlgorithm::ReportError()                     */
1468
/************************************************************************/
1469

1470
//! @cond Doxygen_Suppress
1471
void GDALAlgorithm::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
154✔
1472
                                const char *fmt, ...) const
1473
{
1474
    va_list args;
1475
    va_start(args, fmt);
154✔
1476
    CPLError(eErrClass, err_no, "%s",
154✔
1477
             std::string(m_name)
154✔
1478
                 .append(": ")
154✔
1479
                 .append(CPLString().vPrintf(fmt, args))
308✔
1480
                 .c_str());
1481
    va_end(args);
154✔
1482
}
154✔
1483

1484
//! @endcond
1485

1486
/************************************************************************/
1487
/*                   GDALAlgorithm::ProcessDatasetArg()                 */
1488
/************************************************************************/
1489

1490
bool GDALAlgorithm::ProcessDatasetArg(GDALAlgorithmArg *arg,
1,096✔
1491
                                      GDALAlgorithm *algForOutput)
1492
{
1493
    bool ret = true;
1,096✔
1494

1495
    const auto updateArg = algForOutput->GetArg(GDAL_ARG_NAME_UPDATE);
1,096✔
1496
    const bool update = (updateArg && updateArg->GetType() == GAAT_BOOLEAN &&
1,656✔
1497
                         updateArg->Get<bool>());
560✔
1498
    const auto overwriteArg = algForOutput->GetArg("overwrite");
1,096✔
1499
    const bool overwrite =
1500
        (arg->IsOutput() && overwriteArg &&
2,017✔
1501
         overwriteArg->GetType() == GAAT_BOOLEAN && overwriteArg->Get<bool>());
2,017✔
1502
    auto outputArg = algForOutput->GetArg(GDAL_ARG_NAME_OUTPUT);
1,096✔
1503
    auto &val = arg->Get<GDALArgDatasetValue>();
1,096✔
1504
    if (!val.GetDatasetRef() && !val.IsNameSet())
1,096✔
1505
    {
1506
        ReportError(CE_Failure, CPLE_AppDefined,
2✔
1507
                    "Argument '%s' has no dataset object or dataset name.",
1508
                    arg->GetName().c_str());
2✔
1509
        ret = false;
2✔
1510
    }
1511
    else if (!val.GetDatasetRef() && arg->AutoOpenDataset() &&
1,745✔
1512
             (!arg->IsOutput() || (arg == outputArg && update && !overwrite)))
651✔
1513
    {
1514
        int flags = val.GetType();
223✔
1515
        bool assignToOutputArg = false;
223✔
1516

1517
        // Check if input and output parameters point to the same
1518
        // filename (for vector datasets)
1519
        if (arg->GetName() == GDAL_ARG_NAME_INPUT && update && !overwrite &&
415✔
1520
            outputArg && outputArg->GetType() == GAAT_DATASET)
415✔
1521
        {
1522
            auto &outputVal = outputArg->Get<GDALArgDatasetValue>();
19✔
1523
            if (!outputVal.GetDatasetRef() &&
38✔
1524
                outputVal.GetName() == val.GetName() &&
38✔
1525
                (outputVal.GetInputFlags() & GADV_OBJECT) != 0)
1✔
1526
            {
1527
                assignToOutputArg = true;
1✔
1528
                flags |= GDAL_OF_UPDATE | GDAL_OF_VERBOSE_ERROR;
1✔
1529
            }
1530
        }
1531

1532
        if (!arg->IsOutput() || val.GetInputFlags() == GADV_NAME)
223✔
1533
            flags |= GDAL_OF_VERBOSE_ERROR;
205✔
1534
        if ((arg == outputArg || !outputArg) && update)
223✔
1535
            flags |= GDAL_OF_UPDATE | GDAL_OF_VERBOSE_ERROR;
19✔
1536

1537
        const auto readOnlyArg = algForOutput->GetArg(GDAL_ARG_NAME_READ_ONLY);
223✔
1538
        const bool readOnly =
1539
            (readOnlyArg && readOnlyArg->GetType() == GAAT_BOOLEAN &&
226✔
1540
             readOnlyArg->Get<bool>());
3✔
1541
        if (readOnly)
223✔
1542
            flags &= ~GDAL_OF_UPDATE;
2✔
1543

1544
        CPLStringList aosOpenOptions;
446✔
1545
        CPLStringList aosAllowedDrivers;
446✔
1546
        if (arg->GetName() == GDAL_ARG_NAME_INPUT)
223✔
1547
        {
1548
            const auto ooArg = GetArg(GDAL_ARG_NAME_OPEN_OPTION);
192✔
1549
            if (ooArg && ooArg->GetType() == GAAT_STRING_LIST)
192✔
1550
                aosOpenOptions =
1551
                    CPLStringList(ooArg->Get<std::vector<std::string>>());
189✔
1552

1553
            const auto ifArg = GetArg(GDAL_ARG_NAME_INPUT_FORMAT);
192✔
1554
            if (ifArg && ifArg->GetType() == GAAT_STRING_LIST)
192✔
1555
                aosAllowedDrivers =
1556
                    CPLStringList(ifArg->Get<std::vector<std::string>>());
189✔
1557
        }
1558

1559
        auto poDS =
1560
            GDALDataset::Open(val.GetName().c_str(), flags,
223✔
1561
                              aosAllowedDrivers.List(), aosOpenOptions.List());
223✔
1562
        if (poDS)
223✔
1563
        {
1564
            if (assignToOutputArg)
208✔
1565
            {
1566
                // Avoid opening twice the same datasource if it is both
1567
                // the input and output.
1568
                // Known to cause problems with at least FGdb, SQLite
1569
                // and GPKG drivers. See #4270
1570
                // Restrict to those 3 drivers. For example it is known
1571
                // to break with the PG driver due to the way it
1572
                // manages transactions.
1573
                auto poDriver = poDS->GetDriver();
1✔
1574
                if (poDriver && (EQUAL(poDriver->GetDescription(), "FileGDB") ||
2✔
1575
                                 EQUAL(poDriver->GetDescription(), "SQLite") ||
1✔
1576
                                 EQUAL(poDriver->GetDescription(), "GPKG")))
1✔
1577
                {
1578
                    outputArg->Get<GDALArgDatasetValue>().Set(poDS);
1✔
1579
                }
1580
            }
1581
            val.Set(poDS);
208✔
1582
            poDS->ReleaseRef();
208✔
1583
        }
1584
        else
1585
        {
1586
            ret = false;
15✔
1587
        }
1588
    }
1589
    return ret;
1,096✔
1590
}
1591

1592
/************************************************************************/
1593
/*                   GDALAlgorithm::ValidateArguments()                 */
1594
/************************************************************************/
1595

1596
bool GDALAlgorithm::ValidateArguments()
935✔
1597
{
1598
    if (m_selectedSubAlg)
935✔
1599
        return m_selectedSubAlg->ValidateArguments();
3✔
1600

1601
    if (m_specialActionRequested)
932✔
1602
        return true;
1✔
1603

1604
    bool ret = true;
931✔
1605
    std::map<std::string, std::string> mutualExclusionGroupUsed;
931✔
1606
    for (auto &arg : m_args)
15,361✔
1607
    {
1608
        // Check mutually exclusive arguments
1609
        if (arg->IsExplicitlySet())
14,430✔
1610
        {
1611
            const auto &mutualExclusionGroup = arg->GetMutualExclusionGroup();
2,099✔
1612
            if (!mutualExclusionGroup.empty())
2,099✔
1613
            {
1614
                auto oIter =
1615
                    mutualExclusionGroupUsed.find(mutualExclusionGroup);
207✔
1616
                if (oIter != mutualExclusionGroupUsed.end())
207✔
1617
                {
1618
                    ret = false;
5✔
1619
                    ReportError(
10✔
1620
                        CE_Failure, CPLE_AppDefined,
1621
                        "Argument '%s' is mutually exclusive with '%s'.",
1622
                        arg->GetName().c_str(), oIter->second.c_str());
10✔
1623
                }
1624
                else
1625
                {
1626
                    mutualExclusionGroupUsed[mutualExclusionGroup] =
202✔
1627
                        arg->GetName();
404✔
1628
                }
1629
            }
1630
        }
1631

1632
        if (arg->IsRequired() && !arg->IsExplicitlySet() &&
14,436✔
1633
            !arg->HasDefaultValue())
6✔
1634
        {
1635
            ReportError(CE_Failure, CPLE_AppDefined,
6✔
1636
                        "Required argument '%s' has not been specified.",
1637
                        arg->GetName().c_str());
6✔
1638
            ret = false;
6✔
1639
        }
1640
        else if (arg->IsExplicitlySet() && arg->GetType() == GAAT_DATASET)
14,424✔
1641
        {
1642
            if (!ProcessDatasetArg(arg.get(), this))
1,040✔
1643
                ret = false;
16✔
1644
        }
1645
        else if (arg->IsExplicitlySet() &&
14,443✔
1646
                 GDALAlgorithmArgTypeIsList(arg->GetType()))
1,059✔
1647
        {
1648
            int valueCount = 0;
399✔
1649
            if (arg->GetType() == GAAT_STRING_LIST)
399✔
1650
            {
1651
                valueCount = static_cast<int>(
187✔
1652
                    arg->Get<std::vector<std::string>>().size());
187✔
1653
            }
1654
            else if (arg->GetType() == GAAT_INTEGER_LIST)
212✔
1655
            {
1656
                valueCount =
58✔
1657
                    static_cast<int>(arg->Get<std::vector<int>>().size());
58✔
1658
            }
1659
            else if (arg->GetType() == GAAT_REAL_LIST)
154✔
1660
            {
1661
                valueCount =
119✔
1662
                    static_cast<int>(arg->Get<std::vector<double>>().size());
119✔
1663
            }
1664
            else if (arg->GetType() == GAAT_DATASET_LIST)
35✔
1665
            {
1666
                valueCount = static_cast<int>(
35✔
1667
                    arg->Get<std::vector<GDALArgDatasetValue>>().size());
35✔
1668
            }
1669

1670
            if (valueCount != arg->GetMinCount() &&
634✔
1671
                arg->GetMinCount() == arg->GetMaxCount())
235✔
1672
            {
1673
                ReportError(
2✔
1674
                    CE_Failure, CPLE_AppDefined,
1675
                    "%d value(s) have been specified for argument '%s', "
1676
                    "whereas exactly %d were expected.",
1677
                    valueCount, arg->GetName().c_str(), arg->GetMinCount());
1✔
1678
                ret = false;
1✔
1679
            }
1680
            else if (valueCount < arg->GetMinCount())
398✔
1681
            {
1682
                ReportError(
4✔
1683
                    CE_Failure, CPLE_AppDefined,
1684
                    "Only %d value(s) have been specified for argument '%s', "
1685
                    "whereas at least %d were expected.",
1686
                    valueCount, arg->GetName().c_str(), arg->GetMinCount());
2✔
1687
                ret = false;
2✔
1688
            }
1689
            else if (valueCount > arg->GetMaxCount())
396✔
1690
            {
1691
                ReportError(CE_Failure, CPLE_AppDefined,
2✔
1692
                            "%d values have been specified for argument '%s', "
1693
                            "whereas at most %d were expected.",
1694
                            valueCount, arg->GetName().c_str(),
1✔
1695
                            arg->GetMaxCount());
1696
                ret = false;
1✔
1697
            }
1698
        }
1699

1700
        if (arg->IsExplicitlySet() && arg->GetType() == GAAT_DATASET_LIST &&
14,465✔
1701
            arg->AutoOpenDataset())
35✔
1702
        {
1703
            auto &listVal = arg->Get<std::vector<GDALArgDatasetValue>>();
4✔
1704
            for (auto &val : listVal)
8✔
1705
            {
1706
                if (!val.GetDatasetRef() && val.GetName().empty())
4✔
1707
                {
1708
                    ReportError(
1✔
1709
                        CE_Failure, CPLE_AppDefined,
1710
                        "Argument '%s' has no dataset object or dataset name.",
1711
                        arg->GetName().c_str());
1✔
1712
                    ret = false;
1✔
1713
                }
1714
                else if (!val.GetDatasetRef())
3✔
1715
                {
1716
                    int flags = val.GetType() | GDAL_OF_VERBOSE_ERROR;
3✔
1717

1718
                    CPLStringList aosOpenOptions;
6✔
1719
                    CPLStringList aosAllowedDrivers;
6✔
1720
                    if (arg->GetName() == GDAL_ARG_NAME_INPUT)
3✔
1721
                    {
1722
                        const auto ooArg = GetArg(GDAL_ARG_NAME_OPEN_OPTION);
1✔
1723
                        if (ooArg && ooArg->GetType() == GAAT_STRING_LIST)
1✔
1724
                        {
1725
                            aosOpenOptions = CPLStringList(
1✔
1726
                                ooArg->Get<std::vector<std::string>>());
1✔
1727
                        }
1728

1729
                        const auto ifArg = GetArg(GDAL_ARG_NAME_INPUT_FORMAT);
1✔
1730
                        if (ifArg && ifArg->GetType() == GAAT_STRING_LIST)
1✔
1731
                        {
1732
                            aosAllowedDrivers = CPLStringList(
1✔
1733
                                ifArg->Get<std::vector<std::string>>());
1✔
1734
                        }
1735

1736
                        const auto updateArg = GetArg(GDAL_ARG_NAME_UPDATE);
1✔
1737
                        if (updateArg && updateArg->GetType() == GAAT_BOOLEAN &&
2✔
1738
                            updateArg->Get<bool>())
1✔
1739
                        {
1740
                            flags |= GDAL_OF_UPDATE;
1✔
1741
                        }
1742
                    }
1743

1744
                    auto poDS = std::unique_ptr<GDALDataset>(GDALDataset::Open(
1745
                        val.GetName().c_str(), flags, aosAllowedDrivers.List(),
3✔
1746
                        aosOpenOptions.List()));
9✔
1747
                    if (poDS)
3✔
1748
                    {
1749
                        val.Set(std::move(poDS));
2✔
1750
                    }
1751
                    else
1752
                    {
1753
                        ret = false;
1✔
1754
                    }
1755
                }
1756
            }
1757
        }
1758
    }
1759
    return ret;
931✔
1760
}
1761

1762
/************************************************************************/
1763
/*                      GDALAlgorithm::GetArg()                         */
1764
/************************************************************************/
1765

1766
const GDALAlgorithmArg *GDALAlgorithm::GetArg(const std::string &osName) const
6,068✔
1767
{
1768
    const auto nPos = osName.find_first_not_of('-');
6,068✔
1769
    if (nPos == std::string::npos)
6,068✔
1770
        return nullptr;
8✔
1771
    const std::string osKey = osName.substr(nPos);
12,120✔
1772
    {
1773
        const auto oIter = m_mapLongNameToArg.find(osKey);
6,060✔
1774
        if (oIter != m_mapLongNameToArg.end())
6,060✔
1775
            return oIter->second;
4,657✔
1776
    }
1777
    {
1778
        const auto oIter = m_mapShortNameToArg.find(osKey);
1,403✔
1779
        if (oIter != m_mapShortNameToArg.end())
1,403✔
1780
            return oIter->second;
2✔
1781
    }
1782
    return nullptr;
1,401✔
1783
}
1784

1785
/************************************************************************/
1786
/*                   GDALAlgorithm::AddAliasFor()                       */
1787
/************************************************************************/
1788

1789
//! @cond Doxygen_Suppress
1790
void GDALAlgorithm::AddAliasFor(GDALInConstructionAlgorithmArg *arg,
4,150✔
1791
                                const std::string &alias)
1792
{
1793
    if (cpl::contains(m_mapLongNameToArg, alias))
4,150✔
1794
    {
1795
        ReportError(CE_Failure, CPLE_AppDefined, "Name '%s' already declared.",
1✔
1796
                    alias.c_str());
1797
    }
1798
    else
1799
    {
1800
        m_mapLongNameToArg[alias] = arg;
4,149✔
1801
    }
1802
}
4,150✔
1803

1804
//! @endcond
1805

1806
/************************************************************************/
1807
/*                   GDALAlgorithm::SetPositional()                     */
1808
/************************************************************************/
1809

1810
//! @cond Doxygen_Suppress
1811
void GDALAlgorithm::SetPositional(GDALInConstructionAlgorithmArg *arg)
1,133✔
1812
{
1813
    CPLAssert(std::find(m_positionalArgs.begin(), m_positionalArgs.end(),
1,133✔
1814
                        arg) == m_positionalArgs.end());
1815
    m_positionalArgs.push_back(arg);
1,133✔
1816
}
1,133✔
1817

1818
//! @endcond
1819

1820
/************************************************************************/
1821
/*                     GDALAlgorithm::AddArg()                          */
1822
/************************************************************************/
1823

1824
GDALInConstructionAlgorithmArg &
1825
GDALAlgorithm::AddArg(std::unique_ptr<GDALInConstructionAlgorithmArg> arg)
16,742✔
1826
{
1827
    auto argRaw = arg.get();
16,742✔
1828
    const auto &longName = argRaw->GetName();
16,742✔
1829
    if (!longName.empty())
16,742✔
1830
    {
1831
        if (longName[0] == '-')
16,739✔
1832
        {
1833
            ReportError(CE_Failure, CPLE_AppDefined,
1✔
1834
                        "Long name '%s' should not start with '-'",
1835
                        longName.c_str());
1836
        }
1837
        if (longName.find('=') != std::string::npos)
16,739✔
1838
        {
1839
            ReportError(CE_Failure, CPLE_AppDefined,
1✔
1840
                        "Long name '%s' should not contain a '=' character",
1841
                        longName.c_str());
1842
        }
1843
        if (cpl::contains(m_mapLongNameToArg, longName))
16,739✔
1844
        {
1845
            ReportError(CE_Failure, CPLE_AppDefined,
1✔
1846
                        "Long name '%s' already declared", longName.c_str());
1847
        }
1848
        m_mapLongNameToArg[longName] = argRaw;
16,739✔
1849
    }
1850
    const auto &shortName = argRaw->GetShortName();
16,742✔
1851
    if (!shortName.empty())
16,742✔
1852
    {
1853
        if (shortName.size() != 1 ||
8,132✔
1854
            !((shortName[0] >= 'a' && shortName[0] <= 'z') ||
4,066✔
1855
              (shortName[0] >= 'A' && shortName[0] <= 'Z') ||
3✔
1856
              (shortName[0] >= '0' && shortName[0] <= '9')))
2✔
1857
        {
1858
            ReportError(CE_Failure, CPLE_AppDefined,
1✔
1859
                        "Short name '%s' should be a single letter or digit",
1860
                        shortName.c_str());
1861
        }
1862
        if (cpl::contains(m_mapShortNameToArg, shortName))
4,066✔
1863
        {
1864
            ReportError(CE_Failure, CPLE_AppDefined,
1✔
1865
                        "Short name '%s' already declared", shortName.c_str());
1866
        }
1867
        m_mapShortNameToArg[shortName] = argRaw;
4,066✔
1868
    }
1869
    m_args.emplace_back(std::move(arg));
16,742✔
1870
    return *(
1871
        static_cast<GDALInConstructionAlgorithmArg *>(m_args.back().get()));
16,742✔
1872
}
1873

1874
GDALInConstructionAlgorithmArg &
1875
GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
8,893✔
1876
                      const std::string &helpMessage, bool *pValue)
1877
{
1878
    return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
8,893✔
1879
        this,
1880
        GDALAlgorithmArgDecl(longName, chShortName, helpMessage, GAAT_BOOLEAN),
17,786✔
1881
        pValue));
17,786✔
1882
}
1883

1884
GDALInConstructionAlgorithmArg &
1885
GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
2,048✔
1886
                      const std::string &helpMessage, std::string *pValue)
1887
{
1888
    return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
2,048✔
1889
        this,
1890
        GDALAlgorithmArgDecl(longName, chShortName, helpMessage, GAAT_STRING),
4,096✔
1891
        pValue));
4,096✔
1892
}
1893

1894
GDALInConstructionAlgorithmArg &
1895
GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
105✔
1896
                      const std::string &helpMessage, int *pValue)
1897
{
1898
    return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
105✔
1899
        this,
1900
        GDALAlgorithmArgDecl(longName, chShortName, helpMessage, GAAT_INTEGER),
210✔
1901
        pValue));
210✔
1902
}
1903

1904
GDALInConstructionAlgorithmArg &
1905
GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
74✔
1906
                      const std::string &helpMessage, double *pValue)
1907
{
1908
    return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
74✔
1909
        this,
1910
        GDALAlgorithmArgDecl(longName, chShortName, helpMessage, GAAT_REAL),
148✔
1911
        pValue));
148✔
1912
}
1913

1914
GDALInConstructionAlgorithmArg &
1915
GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
1,188✔
1916
                      const std::string &helpMessage,
1917
                      GDALArgDatasetValue *pValue, GDALArgDatasetValueType type)
1918
{
1919
    pValue->SetType(type);
1,188✔
1920
    auto &arg = AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
1,188✔
1921
        this,
1922
        GDALAlgorithmArgDecl(longName, chShortName, helpMessage, GAAT_DATASET),
2,376✔
1923
        pValue));
1,188✔
1924
    pValue->SetOwnerArgument(&arg);
1,188✔
1925
    return arg;
1,188✔
1926
}
1927

1928
GDALInConstructionAlgorithmArg &
1929
GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
3,885✔
1930
                      const std::string &helpMessage,
1931
                      std::vector<std::string> *pValue)
1932
{
1933
    return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
3,885✔
1934
        this,
1935
        GDALAlgorithmArgDecl(longName, chShortName, helpMessage,
7,770✔
1936
                             GAAT_STRING_LIST),
1937
        pValue));
7,770✔
1938
}
1939

1940
GDALInConstructionAlgorithmArg &
1941
GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
149✔
1942
                      const std::string &helpMessage, std::vector<int> *pValue)
1943
{
1944
    return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
149✔
1945
        this,
1946
        GDALAlgorithmArgDecl(longName, chShortName, helpMessage,
298✔
1947
                             GAAT_INTEGER_LIST),
1948
        pValue));
298✔
1949
}
1950

1951
GDALInConstructionAlgorithmArg &
1952
GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
366✔
1953
                      const std::string &helpMessage,
1954
                      std::vector<double> *pValue)
1955
{
1956
    return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
366✔
1957
        this,
1958
        GDALAlgorithmArgDecl(longName, chShortName, helpMessage,
732✔
1959
                             GAAT_REAL_LIST),
1960
        pValue));
732✔
1961
}
1962

1963
GDALInConstructionAlgorithmArg &
1964
GDALAlgorithm::AddArg(const std::string &longName, char chShortName,
34✔
1965
                      const std::string &helpMessage,
1966
                      std::vector<GDALArgDatasetValue> *pValue,
1967
                      GDALArgDatasetValueType)
1968
{
1969
    // FIXME
1970
    // pValue->SetType(type);
1971
    return AddArg(std::make_unique<GDALInConstructionAlgorithmArg>(
34✔
1972
        this,
1973
        GDALAlgorithmArgDecl(longName, chShortName, helpMessage,
68✔
1974
                             GAAT_DATASET_LIST),
1975
        pValue));
68✔
1976
}
1977

1978
/************************************************************************/
1979
/*                 GDALAlgorithm::AddInputDatasetArg()                  */
1980
/************************************************************************/
1981

1982
GDALInConstructionAlgorithmArg &
1983
GDALAlgorithm::AddInputDatasetArg(GDALArgDatasetValue *pValue,
575✔
1984
                                  GDALArgDatasetValueType type,
1985
                                  bool positionalAndRequired)
1986
{
1987
    auto &arg = AddArg(GDAL_ARG_NAME_INPUT, 'i',
1988
                       CPLSPrintf("Input %s dataset",
1989
                                  GDALArgDatasetValueTypeName(type).c_str()),
575✔
1990
                       pValue, type);
1,150✔
1991
    if (positionalAndRequired)
575✔
1992
        arg.SetPositional().SetRequired();
456✔
1993

1994
    arg.SetAutoCompleteFunction(
1995
        [type](const std::string &currentValue)
1,080✔
1996
        {
1997
            std::vector<std::string> oRet;
3✔
1998

1999
            auto poDM = GetGDALDriverManager();
3✔
2000
            std::set<std::string> oExtensions;
6✔
2001
            for (int i = 0; i < poDM->GetDriverCount(); ++i)
660✔
2002
            {
2003
                auto poDriver = poDM->GetDriver(i);
657✔
2004
                if (((type & GDAL_OF_RASTER) != 0 &&
1,971✔
2005
                     poDriver->GetMetadataItem(GDAL_DCAP_RASTER)) ||
657✔
2006
                    ((type & GDAL_OF_VECTOR) != 0 &&
210✔
2007
                     poDriver->GetMetadataItem(GDAL_DCAP_VECTOR)) ||
1,314✔
2008
                    ((type & GDAL_OF_MULTIDIM_RASTER) != 0 &&
210✔
2009
                     poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER)))
×
2010
                {
2011
                    const char *pszExtensions =
2012
                        poDriver->GetMetadataItem(GDAL_DMD_EXTENSIONS);
447✔
2013
                    if (pszExtensions)
447✔
2014
                    {
2015
                        const CPLStringList aosExts(
2016
                            CSLTokenizeString2(pszExtensions, " ", 0));
576✔
2017
                        for (const char *pszExt : cpl::Iterate(aosExts))
642✔
2018
                            oExtensions.insert(CPLString(pszExt).tolower());
354✔
2019
                    }
2020
                }
2021
            }
2022

2023
            std::string osDir = CPLGetDirnameSafe(currentValue.c_str());
6✔
2024
            auto psDir = VSIOpenDir(osDir.c_str(), 0, nullptr);
3✔
2025
            const std::string osSep = VSIGetDirectorySeparator(osDir.c_str());
6✔
2026
            if (currentValue.empty())
3✔
2027
                osDir.clear();
1✔
2028
            const std::string currentFilename =
2029
                CPLGetFilename(currentValue.c_str());
6✔
2030
            if (psDir)
3✔
2031
            {
2032
                while (const VSIDIREntry *psEntry = VSIGetNextDirEntry(psDir))
124✔
2033
                {
2034
                    if ((currentFilename.empty() ||
121✔
2035
                         STARTS_WITH(psEntry->pszName,
×
2036
                                     currentFilename.c_str())) &&
121✔
2037
                        strcmp(psEntry->pszName, ".") != 0 &&
121✔
2038
                        strcmp(psEntry->pszName, "..") != 0 &&
363✔
2039
                        !strstr(psEntry->pszName, ".aux.xml"))
121✔
2040
                    {
2041
                        if (cpl::contains(
360✔
2042
                                oExtensions,
2043
                                CPLString(CPLGetExtensionSafe(psEntry->pszName))
240✔
2044
                                    .tolower()) ||
337✔
2045
                            VSI_ISDIR(psEntry->nMode))
97✔
2046
                        {
2047
                            std::string osVal;
54✔
2048
                            if (osDir.empty())
27✔
2049
                                osVal = psEntry->pszName;
4✔
2050
                            else
2051
                                osVal = CPLFormFilenameSafe(
46✔
2052
                                    osDir.c_str(), psEntry->pszName, nullptr);
46✔
2053
                            if (VSI_ISDIR(psEntry->nMode))
27✔
2054
                                osVal += osSep;
4✔
2055
                            oRet.push_back(osVal);
27✔
2056
                        }
2057
                    }
2058
                }
121✔
2059
                VSICloseDir(psDir);
3✔
2060
            }
2061
            return oRet;
6✔
2062
        });
575✔
2063

2064
    return arg;
575✔
2065
}
2066

2067
/************************************************************************/
2068
/*                 GDALAlgorithm::AddInputDatasetArg()                  */
2069
/************************************************************************/
2070

2071
GDALInConstructionAlgorithmArg &
2072
GDALAlgorithm::AddInputDatasetArg(std::vector<GDALArgDatasetValue> *pValue,
1✔
2073
                                  GDALArgDatasetValueType type,
2074
                                  bool positionalAndRequired)
2075
{
2076
    auto &arg = AddArg(GDAL_ARG_NAME_INPUT, 'i',
2077
                       CPLSPrintf("Input %s datasets",
2078
                                  GDALArgDatasetValueTypeName(type).c_str()),
1✔
2079
                       pValue, type);
2✔
2080
    if (positionalAndRequired)
1✔
2081
        arg.SetPositional().SetRequired();
1✔
2082
    return arg;
1✔
2083
}
2084

2085
/************************************************************************/
2086
/*                 GDALAlgorithm::AddOutputDatasetArg()                 */
2087
/************************************************************************/
2088

2089
GDALInConstructionAlgorithmArg &
2090
GDALAlgorithm::AddOutputDatasetArg(GDALArgDatasetValue *pValue,
525✔
2091
                                   GDALArgDatasetValueType type,
2092
                                   bool positionalAndRequired)
2093
{
2094
    pValue->SetInputFlags(GADV_NAME);
525✔
2095
    pValue->SetOutputFlags(GADV_OBJECT);
525✔
2096
    auto &arg = AddArg(GDAL_ARG_NAME_OUTPUT, 'o',
2097
                       CPLSPrintf("Output %s dataset",
2098
                                  GDALArgDatasetValueTypeName(type).c_str()),
525✔
2099
                       pValue, type)
1,575✔
2100
                    .SetIsInput(true)
525✔
2101
                    .SetIsOutput(true);
525✔
2102
    if (positionalAndRequired)
525✔
2103
        arg.SetPositional().SetRequired();
406✔
2104
    return arg;
525✔
2105
}
2106

2107
/************************************************************************/
2108
/*                 GDALAlgorithm::AddOverwriteArg()                     */
2109
/************************************************************************/
2110

2111
GDALInConstructionAlgorithmArg &GDALAlgorithm::AddOverwriteArg(bool *pValue)
503✔
2112
{
2113
    return AddArg("overwrite", 0,
2114
                  _("Whether overwriting existing output is allowed"), pValue)
1,006✔
2115
        .SetDefault(false);
1,006✔
2116
}
2117

2118
/************************************************************************/
2119
/*                 GDALAlgorithm::AddUpdateArg()                        */
2120
/************************************************************************/
2121

2122
GDALInConstructionAlgorithmArg &GDALAlgorithm::AddUpdateArg(bool *pValue)
274✔
2123
{
2124
    return AddArg(GDAL_ARG_NAME_UPDATE, 0,
2125
                  _("Whether to open existing dataset in update mode"), pValue)
548✔
2126
        .SetDefault(false);
548✔
2127
}
2128

2129
/************************************************************************/
2130
/*                          AddOptionsSuggestions()                     */
2131
/************************************************************************/
2132

2133
static bool AddOptionsSuggestions(const char *pszXML, int datasetType,
19✔
2134
                                  const std::string &currentValue,
2135
                                  std::vector<std::string> &oRet)
2136
{
2137
    if (!pszXML)
19✔
2138
        return false;
×
2139
    CPLXMLTreeCloser poTree(CPLParseXMLString(pszXML));
38✔
2140
    if (!poTree)
19✔
2141
        return false;
×
2142
    const CPLXMLNode *psRoot =
2143
        CPLGetXMLNode(poTree.get(), "=CreationOptionList");
19✔
2144
    if (!psRoot)
19✔
2145
        psRoot = CPLGetXMLNode(poTree.get(), "=LayerCreationOptionList");
4✔
2146
    if (!psRoot)
19✔
2147
        psRoot = CPLGetXMLNode(poTree.get(), "=OpenOptionList");
2✔
2148
    if (!psRoot)
19✔
2149
        return false;
×
2150

2151
    for (const CPLXMLNode *psChild = psRoot->psChild; psChild;
309✔
2152
         psChild = psChild->psNext)
290✔
2153
    {
2154
        const char *pszName = CPLGetXMLValue(psChild, "name", nullptr);
300✔
2155
        if (pszName && currentValue == pszName &&
310✔
2156
            EQUAL(psChild->pszValue, "Option"))
10✔
2157
        {
2158
            const char *pszType = CPLGetXMLValue(psChild, "type", "");
10✔
2159
            const char *pszMin = CPLGetXMLValue(psChild, "min", nullptr);
10✔
2160
            const char *pszMax = CPLGetXMLValue(psChild, "max", nullptr);
10✔
2161
            if (EQUAL(pszType, "string-select"))
10✔
2162
            {
2163
                for (const CPLXMLNode *psChild2 = psChild->psChild; psChild2;
72✔
2164
                     psChild2 = psChild2->psNext)
68✔
2165
                {
2166
                    if (EQUAL(psChild2->pszValue, "Value"))
68✔
2167
                    {
2168
                        oRet.push_back(CPLGetXMLValue(psChild2, "", ""));
60✔
2169
                    }
2170
                }
2171
            }
2172
            else if (EQUAL(pszType, "boolean"))
6✔
2173
            {
2174
                oRet.push_back("NO");
1✔
2175
                oRet.push_back("YES");
1✔
2176
            }
2177
            else if (EQUAL(pszType, "int"))
5✔
2178
            {
2179
                if (pszMin && pszMax && atoi(pszMax) - atoi(pszMin) > 0 &&
5✔
2180
                    atoi(pszMax) - atoi(pszMin) < 25)
2✔
2181
                {
2182
                    const int nMax = atoi(pszMax);
1✔
2183
                    for (int i = atoi(pszMin); i <= nMax; ++i)
13✔
2184
                        oRet.push_back(std::to_string(i));
12✔
2185
                }
2186
            }
2187

2188
            if (oRet.empty())
10✔
2189
            {
2190
                if (pszMin && pszMax)
4✔
2191
                {
2192
                    oRet.push_back(std::string("##"));
1✔
2193
                    oRet.push_back(std::string("validity range: [")
2✔
2194
                                       .append(pszMin)
1✔
2195
                                       .append(",")
1✔
2196
                                       .append(pszMax)
1✔
2197
                                       .append("]"));
1✔
2198
                }
2199
                else if (pszMin)
3✔
2200
                {
2201
                    oRet.push_back(std::string("##"));
1✔
2202
                    oRet.push_back(
1✔
2203
                        std::string("validity range: >= ").append(pszMin));
1✔
2204
                }
2205
                else if (pszMax)
2✔
2206
                {
2207
                    oRet.push_back(std::string("##"));
1✔
2208
                    oRet.push_back(
1✔
2209
                        std::string("validity range: <= ").append(pszMax));
1✔
2210
                }
2211
                else if (const char *pszDescription =
1✔
2212
                             CPLGetXMLValue(psChild, "description", nullptr))
1✔
2213
                {
2214
                    oRet.push_back(std::string("##"));
1✔
2215
                    oRet.push_back(std::string("type: ")
2✔
2216
                                       .append(pszType)
1✔
2217
                                       .append(", description: ")
1✔
2218
                                       .append(pszDescription));
1✔
2219
                }
2220
            }
2221

2222
            return true;
10✔
2223
        }
2224
    }
2225

2226
    for (const CPLXMLNode *psChild = psRoot->psChild; psChild;
229✔
2227
         psChild = psChild->psNext)
220✔
2228
    {
2229
        const char *pszName = CPLGetXMLValue(psChild, "name", nullptr);
220✔
2230
        if (pszName && EQUAL(psChild->pszValue, "Option"))
220✔
2231
        {
2232
            const char *pszScope = CPLGetXMLValue(psChild, "scope", nullptr);
220✔
2233
            if (!pszScope ||
220✔
2234
                (EQUAL(pszScope, "raster") &&
40✔
2235
                 (datasetType & GDAL_OF_RASTER) != 0) ||
40✔
2236
                (EQUAL(pszScope, "vector") &&
20✔
2237
                 (datasetType & GDAL_OF_VECTOR) != 0))
×
2238
            {
2239
                oRet.push_back(std::string(pszName).append("="));
200✔
2240
            }
2241
        }
2242
    }
2243

2244
    return false;
9✔
2245
}
2246

2247
/************************************************************************/
2248
/*                 GDALAlgorithm::AddOpenOptionsArg()                   */
2249
/************************************************************************/
2250

2251
GDALInConstructionAlgorithmArg &
2252
GDALAlgorithm::AddOpenOptionsArg(std::vector<std::string> *pValue)
553✔
2253
{
2254
    auto &arg = AddArg(GDAL_ARG_NAME_OPEN_OPTION, 0, _("Open options"), pValue)
1,106✔
2255
                    .AddAlias("oo")
1,106✔
2256
                    .SetMetaVar("KEY=VALUE")
1,106✔
2257
                    .SetCategory(GAAC_ADVANCED);
553✔
2258

2259
    arg.SetAutoCompleteFunction(
2260
        [this](const std::string &currentValue)
6✔
2261
        {
2262
            std::vector<std::string> oRet;
2✔
2263

2264
            int datasetType =
2✔
2265
                GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_MULTIDIM_RASTER;
2266
            auto inputArg = GetArg(GDAL_ARG_NAME_INPUT);
2✔
2267
            if (inputArg && inputArg->GetType() == GAAT_DATASET)
2✔
2268
            {
2269
                auto &datasetValue = inputArg->Get<GDALArgDatasetValue>();
2✔
2270
                datasetType = datasetValue.GetType();
2✔
2271
            }
2272

2273
            auto inputFormat = GetArg(GDAL_ARG_NAME_INPUT_FORMAT);
2✔
2274
            if (inputFormat && inputFormat->GetType() == GAAT_STRING_LIST &&
4✔
2275
                inputFormat->IsExplicitlySet())
2✔
2276
            {
2277
                const auto &aosAllowedDrivers =
2278
                    inputFormat->Get<std::vector<std::string>>();
1✔
2279
                if (aosAllowedDrivers.size() == 1)
1✔
2280
                {
2281
                    auto poDriver = GetGDALDriverManager()->GetDriverByName(
2✔
2282
                        aosAllowedDrivers[0].c_str());
1✔
2283
                    if (poDriver)
1✔
2284
                    {
2285
                        AddOptionsSuggestions(
1✔
2286
                            poDriver->GetMetadataItem(GDAL_DMD_OPENOPTIONLIST),
1✔
2287
                            datasetType, currentValue, oRet);
2288
                    }
2289
                    return oRet;
1✔
2290
                }
2291
            }
2292

2293
            if (inputArg && inputArg->GetType() == GAAT_DATASET)
1✔
2294
            {
2295
                auto poDM = GetGDALDriverManager();
1✔
2296
                auto &datasetValue = inputArg->Get<GDALArgDatasetValue>();
1✔
2297
                const auto &osDSName = datasetValue.GetName();
1✔
2298
                const std::string osExt = CPLGetExtensionSafe(osDSName.c_str());
1✔
2299
                if (!osExt.empty())
1✔
2300
                {
2301
                    std::set<std::string> oVisitedExtensions;
1✔
2302
                    for (int i = 0; i < poDM->GetDriverCount(); ++i)
220✔
2303
                    {
2304
                        auto poDriver = poDM->GetDriver(i);
219✔
2305
                        if (((datasetType & GDAL_OF_RASTER) != 0 &&
657✔
2306
                             poDriver->GetMetadataItem(GDAL_DCAP_RASTER)) ||
219✔
2307
                            ((datasetType & GDAL_OF_VECTOR) != 0 &&
70✔
2308
                             poDriver->GetMetadataItem(GDAL_DCAP_VECTOR)) ||
438✔
2309
                            ((datasetType & GDAL_OF_MULTIDIM_RASTER) != 0 &&
70✔
2310
                             poDriver->GetMetadataItem(
×
2311
                                 GDAL_DCAP_MULTIDIM_RASTER)))
×
2312
                        {
2313
                            const char *pszExtensions =
2314
                                poDriver->GetMetadataItem(GDAL_DMD_EXTENSIONS);
149✔
2315
                            if (pszExtensions)
149✔
2316
                            {
2317
                                const CPLStringList aosExts(
2318
                                    CSLTokenizeString2(pszExtensions, " ", 0));
96✔
2319
                                for (const char *pszExt : cpl::Iterate(aosExts))
212✔
2320
                                {
2321
                                    if (EQUAL(pszExt, osExt.c_str()) &&
120✔
2322
                                        !cpl::contains(oVisitedExtensions,
3✔
2323
                                                       pszExt))
2324
                                    {
2325
                                        oVisitedExtensions.insert(pszExt);
1✔
2326
                                        if (AddOptionsSuggestions(
1✔
2327
                                                poDriver->GetMetadataItem(
2328
                                                    GDAL_DMD_OPENOPTIONLIST),
1✔
2329
                                                datasetType, currentValue,
2330
                                                oRet))
2331
                                        {
2332
                                            return oRet;
×
2333
                                        }
2334
                                        break;
1✔
2335
                                    }
2336
                                }
2337
                            }
2338
                        }
2339
                    }
2340
                }
2341
            }
2342

2343
            return oRet;
1✔
2344
        });
553✔
2345

2346
    return arg;
553✔
2347
}
2348

2349
/************************************************************************/
2350
/*                            ValidateFormat()                          */
2351
/************************************************************************/
2352

2353
bool GDALAlgorithm::ValidateFormat(const GDALAlgorithmArg &arg,
105✔
2354
                                   bool bStreamAllowed) const
2355
{
2356
    if (arg.GetChoices().empty())
105✔
2357
    {
2358
        const auto Validate =
2359
            [this, &arg, bStreamAllowed](const std::string &val)
161✔
2360
        {
2361
            if (bStreamAllowed && val == "stream")
82✔
2362
                return true;
8✔
2363

2364
            auto hDriver = GDALGetDriverByName(val.c_str());
74✔
2365
            if (!hDriver)
74✔
2366
            {
2367
                ReportError(CE_Failure, CPLE_AppDefined,
2✔
2368
                            "Invalid value for argument '%s'. Driver '%s' does "
2369
                            "not exist",
2370
                            arg.GetName().c_str(), val.c_str());
1✔
2371
                return false;
1✔
2372
            }
2373

2374
            const auto caps = arg.GetMetadataItem(GAAMDI_REQUIRED_CAPABILITIES);
73✔
2375
            if (caps)
73✔
2376
            {
2377
                for (const std::string &cap : *caps)
202✔
2378
                {
2379
                    if (!GDALGetMetadataItem(hDriver, cap.c_str(), nullptr))
135✔
2380
                    {
2381
                        if (cap == GDAL_DCAP_CREATECOPY &&
8✔
2382
                            std::find(caps->begin(), caps->end(),
×
2383
                                      GDAL_DCAP_RASTER) != caps->end() &&
3✔
2384
                            GDALGetMetadataItem(hDriver, GDAL_DCAP_RASTER,
3✔
2385
                                                nullptr) &&
8✔
2386
                            GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE,
3✔
2387
                                                nullptr))
2388
                        {
2389
                            // if it supports Create, it supports CreateCopy
2390
                        }
2391
                        else
2392
                        {
2393
                            ReportError(
4✔
2394
                                CE_Failure, CPLE_AppDefined,
2395
                                "Invalid value for argument '%s'. Driver '%s' "
2396
                                "does "
2397
                                "not expose the required '%s' capability.",
2398
                                arg.GetName().c_str(), val.c_str(),
2✔
2399
                                cap.c_str());
2400
                            return false;
2✔
2401
                        }
2402
                    }
2403
                }
2404
            }
2405
            return true;
71✔
2406
        };
82✔
2407

2408
        if (arg.GetType() == GAAT_STRING)
82✔
2409
        {
2410
            return Validate(arg.Get<std::string>());
80✔
2411
        }
2412
        else if (arg.GetType() == GAAT_STRING_LIST)
4✔
2413
        {
2414
            for (const auto &val : arg.Get<std::vector<std::string>>())
6✔
2415
            {
2416
                if (!Validate(val))
4✔
2417
                    return false;
2✔
2418
            }
2419
        }
2420
    }
2421

2422
    return true;
25✔
2423
}
2424

2425
/************************************************************************/
2426
/*                    FormatAutoCompleteFunction()                      */
2427
/************************************************************************/
2428

2429
static std::vector<std::string>
2430
FormatAutoCompleteFunction(const GDALAlgorithmArg &arg)
1✔
2431
{
2432
    std::vector<std::string> res;
1✔
2433
    auto poDM = GetGDALDriverManager();
1✔
2434
    for (int i = 0; i < poDM->GetDriverCount(); ++i)
220✔
2435
    {
2436
        auto poDriver = poDM->GetDriver(i);
219✔
2437

2438
        const auto caps = arg.GetMetadataItem(GAAMDI_REQUIRED_CAPABILITIES);
219✔
2439
        if (caps)
219✔
2440
        {
2441
            bool ok = true;
219✔
2442
            for (const std::string &cap : *caps)
437✔
2443
            {
2444
                if (poDriver->GetMetadataItem(cap.c_str()))
368✔
2445
                {
2446
                }
2447
                else if (cap == GDAL_DCAP_CREATECOPY &&
266✔
2448
                         std::find(caps->begin(), caps->end(),
×
2449
                                   GDAL_DCAP_RASTER) != caps->end() &&
98✔
2450
                         poDriver->GetMetadataItem(GDAL_DCAP_RASTER) &&
364✔
2451
                         poDriver->GetMetadataItem(GDAL_DCAP_CREATE))
98✔
2452
                {
2453
                    // if it supports Create, it supports CreateCopy
2454
                }
2455
                else
2456
                {
2457
                    ok = false;
150✔
2458
                    break;
150✔
2459
                }
2460
            }
2461
            if (ok)
219✔
2462
            {
2463
                res.push_back(poDriver->GetDescription());
69✔
2464
            }
2465
        }
2466
    }
2467
    return res;
1✔
2468
}
2469

2470
/************************************************************************/
2471
/*                 GDALAlgorithm::AddInputFormatsArg()                  */
2472
/************************************************************************/
2473

2474
GDALInConstructionAlgorithmArg &
2475
GDALAlgorithm::AddInputFormatsArg(std::vector<std::string> *pValue)
540✔
2476
{
2477
    auto &arg =
2478
        AddArg(GDAL_ARG_NAME_INPUT_FORMAT, 0, _("Input formats"), pValue)
1,080✔
2479
            .AddAlias("if")
1,080✔
2480
            .SetCategory(GAAC_ADVANCED);
540✔
2481
    arg.AddValidationAction([this, &arg]()
4✔
2482
                            { return ValidateFormat(arg, false); });
544✔
2483
    arg.SetAutoCompleteFunction([&arg](const std::string &)
×
2484
                                { return FormatAutoCompleteFunction(arg); });
540✔
2485
    return arg;
540✔
2486
}
2487

2488
/************************************************************************/
2489
/*                 GDALAlgorithm::AddOutputFormatArg()                  */
2490
/************************************************************************/
2491

2492
GDALInConstructionAlgorithmArg &
2493
GDALAlgorithm::AddOutputFormatArg(std::string *pValue, bool bStreamAllowed)
632✔
2494
{
2495
    auto &arg = AddArg(GDAL_ARG_NAME_OUTPUT_FORMAT, 'f',
2496
                       bStreamAllowed ? _("Output format (\"stream\" allowed)")
2497
                                      : _("Output format"),
2498
                       pValue)
1,264✔
2499
                    .AddAlias("of")
1,264✔
2500
                    .AddAlias("format");
632✔
2501
    arg.AddValidationAction([this, &arg, bStreamAllowed]()
101✔
2502
                            { return ValidateFormat(arg, bStreamAllowed); });
733✔
2503
    arg.SetAutoCompleteFunction([&arg](const std::string &)
1✔
2504
                                { return FormatAutoCompleteFunction(arg); });
633✔
2505
    return arg;
632✔
2506
}
2507

2508
/************************************************************************/
2509
/*                 GDALAlgorithm::AddOutputDataTypeArg()                */
2510
/************************************************************************/
2511
GDALInConstructionAlgorithmArg &
2512
GDALAlgorithm::AddOutputDataTypeArg(std::string *pValue)
31✔
2513
{
2514
    auto &arg =
2515
        AddArg(GDAL_ARG_NAME_OUTPUT_DATA_TYPE, 0, _("Output data type"), pValue)
62✔
2516
            .AddAlias("ot")
62✔
2517
            .AddAlias("datatype")
62✔
2518
            .SetChoices("Byte", "Int8", "UInt16", "Int16", "UInt32", "Int32",
2519
                        "UInt64", "Int64", "CInt16", "CInt32", "Float32",
2520
                        "Float64", "CFloat32", "CFloat64");
31✔
2521
    return arg;
31✔
2522
}
2523

2524
/************************************************************************/
2525
/*                 GDALAlgorithm::AddOutputStringArg()                  */
2526
/************************************************************************/
2527

2528
GDALInConstructionAlgorithmArg &
2529
GDALAlgorithm::AddOutputStringArg(std::string *pValue)
80✔
2530
{
2531
    return AddArg("output-string", 0,
2532
                  _("Output string, in which the result is placed"), pValue)
160✔
2533
        .SetHiddenForCLI()
80✔
2534
        .SetIsInput(false)
80✔
2535
        .SetIsOutput(true);
160✔
2536
}
2537

2538
/************************************************************************/
2539
/*                    GDALAlgorithm::AddLayerNameArg()                  */
2540
/************************************************************************/
2541

2542
GDALInConstructionAlgorithmArg &
2543
GDALAlgorithm::AddLayerNameArg(std::string *pValue)
14✔
2544
{
2545
    return AddArg("layer", 'l', _("Layer name"), pValue);
14✔
2546
}
2547

2548
/************************************************************************/
2549
/*                    GDALAlgorithm::AddLayerNameArg()                  */
2550
/************************************************************************/
2551

2552
GDALInConstructionAlgorithmArg &
2553
GDALAlgorithm::AddLayerNameArg(std::vector<std::string> *pValue)
36✔
2554
{
2555
    return AddArg("layer", 'l', _("Layer name"), pValue);
36✔
2556
}
2557

2558
/************************************************************************/
2559
/*                          ValidateKeyValue()                          */
2560
/************************************************************************/
2561

2562
bool GDALAlgorithm::ValidateKeyValue(const GDALAlgorithmArg &arg) const
17✔
2563
{
2564
    const auto Validate = [this, &arg](const std::string &val)
24✔
2565
    {
2566
        if (val.find('=') == std::string::npos)
22✔
2567
        {
2568
            ReportError(
2✔
2569
                CE_Failure, CPLE_AppDefined,
2570
                "Invalid value for argument '%s'. <KEY>=<VALUE> expected",
2571
                arg.GetName().c_str());
2✔
2572
            return false;
2✔
2573
        }
2574

2575
        return true;
20✔
2576
    };
17✔
2577

2578
    if (arg.GetType() == GAAT_STRING)
17✔
2579
    {
2580
        return Validate(arg.Get<std::string>());
×
2581
    }
2582
    else if (arg.GetType() == GAAT_STRING_LIST)
17✔
2583
    {
2584
        for (const auto &val : arg.Get<std::vector<std::string>>())
37✔
2585
        {
2586
            if (!Validate(val))
22✔
2587
                return false;
2✔
2588
        }
2589
    }
2590

2591
    return true;
15✔
2592
}
2593

2594
/************************************************************************/
2595
/*                 GDALAlgorithm::AddCreationOptionsArg()               */
2596
/************************************************************************/
2597

2598
GDALInConstructionAlgorithmArg &
2599
GDALAlgorithm::AddCreationOptionsArg(std::vector<std::string> *pValue)
518✔
2600
{
2601
    auto &arg = AddArg("creation-option", 0, _("Creation option"), pValue)
1,036✔
2602
                    .AddAlias("co")
1,036✔
2603
                    .SetMetaVar("<KEY>=<VALUE>");
518✔
2604
    arg.AddValidationAction([this, &arg]() { return ValidateKeyValue(arg); });
528✔
2605

2606
    arg.SetAutoCompleteFunction(
2607
        [this](const std::string &currentValue)
45✔
2608
        {
2609
            std::vector<std::string> oRet;
15✔
2610

2611
            int datasetType =
15✔
2612
                GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_MULTIDIM_RASTER;
2613
            auto outputArg = GetArg(GDAL_ARG_NAME_OUTPUT);
15✔
2614
            if (outputArg && outputArg->GetType() == GAAT_DATASET)
15✔
2615
            {
2616
                auto &datasetValue = outputArg->Get<GDALArgDatasetValue>();
15✔
2617
                datasetType = datasetValue.GetType();
15✔
2618
            }
2619

2620
            auto outputFormat = GetArg(GDAL_ARG_NAME_OUTPUT_FORMAT);
15✔
2621
            if (outputFormat && outputFormat->GetType() == GAAT_STRING &&
30✔
2622
                outputFormat->IsExplicitlySet())
15✔
2623
            {
2624
                auto poDriver = GetGDALDriverManager()->GetDriverByName(
12✔
2625
                    outputFormat->Get<std::string>().c_str());
6✔
2626
                if (poDriver)
6✔
2627
                {
2628
                    AddOptionsSuggestions(
6✔
2629
                        poDriver->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST),
6✔
2630
                        datasetType, currentValue, oRet);
2631
                }
2632
                return oRet;
6✔
2633
            }
2634

2635
            if (outputArg && outputArg->GetType() == GAAT_DATASET)
9✔
2636
            {
2637
                auto poDM = GetGDALDriverManager();
9✔
2638
                auto &datasetValue = outputArg->Get<GDALArgDatasetValue>();
9✔
2639
                const auto &osDSName = datasetValue.GetName();
9✔
2640
                const std::string osExt = CPLGetExtensionSafe(osDSName.c_str());
9✔
2641
                if (!osExt.empty())
9✔
2642
                {
2643
                    std::set<std::string> oVisitedExtensions;
9✔
2644
                    for (int i = 0; i < poDM->GetDriverCount(); ++i)
475✔
2645
                    {
2646
                        auto poDriver = poDM->GetDriver(i);
473✔
2647
                        if (((datasetType & GDAL_OF_RASTER) != 0 &&
1,419✔
2648
                             poDriver->GetMetadataItem(GDAL_DCAP_RASTER)) ||
473✔
2649
                            ((datasetType & GDAL_OF_VECTOR) != 0 &&
140✔
2650
                             poDriver->GetMetadataItem(GDAL_DCAP_VECTOR)) ||
946✔
2651
                            ((datasetType & GDAL_OF_MULTIDIM_RASTER) != 0 &&
140✔
2652
                             poDriver->GetMetadataItem(
×
2653
                                 GDAL_DCAP_MULTIDIM_RASTER)))
×
2654
                        {
2655
                            const char *pszExtensions =
2656
                                poDriver->GetMetadataItem(GDAL_DMD_EXTENSIONS);
333✔
2657
                            if (pszExtensions)
333✔
2658
                            {
2659
                                const CPLStringList aosExts(
2660
                                    CSLTokenizeString2(pszExtensions, " ", 0));
213✔
2661
                                for (const char *pszExt : cpl::Iterate(aosExts))
473✔
2662
                                {
2663
                                    if (EQUAL(pszExt, osExt.c_str()) &&
282✔
2664
                                        !cpl::contains(oVisitedExtensions,
13✔
2665
                                                       pszExt))
2666
                                    {
2667
                                        oVisitedExtensions.insert(pszExt);
9✔
2668
                                        if (AddOptionsSuggestions(
9✔
2669
                                                poDriver->GetMetadataItem(
2670
                                                    GDAL_DMD_CREATIONOPTIONLIST),
9✔
2671
                                                datasetType, currentValue,
2672
                                                oRet))
2673
                                        {
2674
                                            return oRet;
7✔
2675
                                        }
2676
                                        break;
2✔
2677
                                    }
2678
                                }
2679
                            }
2680
                        }
2681
                    }
2682
                }
2683
            }
2684

2685
            return oRet;
2✔
2686
        });
518✔
2687

2688
    return arg;
518✔
2689
}
2690

2691
/************************************************************************/
2692
/*                GDALAlgorithm::AddLayerCreationOptionsArg()           */
2693
/************************************************************************/
2694

2695
GDALInConstructionAlgorithmArg &
2696
GDALAlgorithm::AddLayerCreationOptionsArg(std::vector<std::string> *pValue)
242✔
2697
{
2698
    auto &arg =
2699
        AddArg("layer-creation-option", 0, _("Layer creation option"), pValue)
484✔
2700
            .AddAlias("lco")
484✔
2701
            .SetMetaVar("<KEY>=<VALUE>");
242✔
2702
    arg.AddValidationAction([this, &arg]() { return ValidateKeyValue(arg); });
246✔
2703

2704
    arg.SetAutoCompleteFunction(
2705
        [this](const std::string &currentValue)
5✔
2706
        {
2707
            std::vector<std::string> oRet;
2✔
2708

2709
            auto outputFormat = GetArg(GDAL_ARG_NAME_OUTPUT_FORMAT);
2✔
2710
            if (outputFormat && outputFormat->GetType() == GAAT_STRING &&
4✔
2711
                outputFormat->IsExplicitlySet())
2✔
2712
            {
2713
                auto poDriver = GetGDALDriverManager()->GetDriverByName(
2✔
2714
                    outputFormat->Get<std::string>().c_str());
1✔
2715
                if (poDriver)
1✔
2716
                {
2717
                    AddOptionsSuggestions(poDriver->GetMetadataItem(
1✔
2718
                                              GDAL_DS_LAYER_CREATIONOPTIONLIST),
1✔
2719
                                          GDAL_OF_VECTOR, currentValue, oRet);
2720
                }
2721
                return oRet;
1✔
2722
            }
2723

2724
            auto outputArg = GetArg(GDAL_ARG_NAME_OUTPUT);
1✔
2725
            if (outputArg && outputArg->GetType() == GAAT_DATASET)
1✔
2726
            {
2727
                auto poDM = GetGDALDriverManager();
1✔
2728
                auto &datasetValue = outputArg->Get<GDALArgDatasetValue>();
1✔
2729
                const auto &osDSName = datasetValue.GetName();
1✔
2730
                const std::string osExt = CPLGetExtensionSafe(osDSName.c_str());
1✔
2731
                if (!osExt.empty())
1✔
2732
                {
2733
                    std::set<std::string> oVisitedExtensions;
1✔
2734
                    for (int i = 0; i < poDM->GetDriverCount(); ++i)
220✔
2735
                    {
2736
                        auto poDriver = poDM->GetDriver(i);
219✔
2737
                        if (poDriver->GetMetadataItem(GDAL_DCAP_VECTOR))
219✔
2738
                        {
2739
                            const char *pszExtensions =
2740
                                poDriver->GetMetadataItem(GDAL_DMD_EXTENSIONS);
87✔
2741
                            if (pszExtensions)
87✔
2742
                            {
2743
                                const CPLStringList aosExts(
2744
                                    CSLTokenizeString2(pszExtensions, " ", 0));
60✔
2745
                                for (const char *pszExt : cpl::Iterate(aosExts))
152✔
2746
                                {
2747
                                    if (EQUAL(pszExt, osExt.c_str()) &&
94✔
2748
                                        !cpl::contains(oVisitedExtensions,
1✔
2749
                                                       pszExt))
2750
                                    {
2751
                                        oVisitedExtensions.insert(pszExt);
1✔
2752
                                        if (AddOptionsSuggestions(
1✔
2753
                                                poDriver->GetMetadataItem(
2754
                                                    GDAL_DS_LAYER_CREATIONOPTIONLIST),
1✔
2755
                                                GDAL_OF_VECTOR, currentValue,
2756
                                                oRet))
2757
                                        {
2758
                                            return oRet;
×
2759
                                        }
2760
                                        break;
1✔
2761
                                    }
2762
                                }
2763
                            }
2764
                        }
2765
                    }
2766
                }
2767
            }
2768

2769
            return oRet;
1✔
2770
        });
242✔
2771

2772
    return arg;
242✔
2773
}
2774

2775
/************************************************************************/
2776
/*                        GDALAlgorithm::AddBBOXArg()                   */
2777
/************************************************************************/
2778

2779
/** Add bbox=xmin,ymin,xmax,ymax argument. */
2780
GDALInConstructionAlgorithmArg &
2781
GDALAlgorithm::AddBBOXArg(std::vector<double> *pValue, const char *helpMessage)
151✔
2782
{
2783
    auto &arg = AddArg("bbox", 0,
2784
                       helpMessage ? helpMessage
2785
                                   : _("Bounding box as xmin,ymin,xmax,ymax"),
2786
                       pValue)
302✔
2787
                    .SetRepeatedArgAllowed(false)
151✔
2788
                    .SetMinCount(4)
151✔
2789
                    .SetMaxCount(4)
151✔
2790
                    .SetDisplayHintAboutRepetition(false);
151✔
2791
    arg.AddValidationAction(
2792
        [&arg]()
26✔
2793
        {
2794
            const auto &val = arg.Get<std::vector<double>>();
26✔
2795
            CPLAssert(val.size() == 4);
26✔
2796
            if (!(val[0] <= val[2]) || !(val[1] <= val[3]))
26✔
2797
            {
2798
                CPLError(CE_Failure, CPLE_AppDefined,
4✔
2799
                         "Value of 'bbox' should be xmin,ymin,xmax,ymax with "
2800
                         "xmin <= xmax and ymin <= ymax");
2801
                return false;
4✔
2802
            }
2803
            return true;
22✔
2804
        });
151✔
2805
    return arg;
151✔
2806
}
2807

2808
/************************************************************************/
2809
/*                  GDALAlgorithm::AddProgressArg()                     */
2810
/************************************************************************/
2811

2812
GDALInConstructionAlgorithmArg &GDALAlgorithm::AddProgressArg()
397✔
2813
{
2814
    return AddArg("progress", 0, _("Display progress bar"),
2815
                  &m_progressBarRequested)
794✔
2816
        .SetOnlyForCLI()
397✔
2817
        .SetCategory(GAAC_COMMON);
794✔
2818
}
2819

2820
/************************************************************************/
2821
/*                       GDALAlgorithm::Run()                           */
2822
/************************************************************************/
2823

2824
bool GDALAlgorithm::Run(GDALProgressFunc pfnProgress, void *pProgressData)
565✔
2825
{
2826
    if (m_selectedSubAlg)
565✔
2827
        return m_selectedSubAlg->Run(pfnProgress, pProgressData);
31✔
2828

2829
    if (m_helpRequested)
534✔
2830
    {
2831
        printf("%s", GetUsageForCLI(false).c_str()); /*ok*/
1✔
2832
        return true;
1✔
2833
    }
2834

2835
    if (m_JSONUsageRequested)
533✔
2836
    {
2837
        printf("%s", GetUsageAsJSON().c_str()); /*ok*/
3✔
2838
        return true;
3✔
2839
    }
2840

2841
    return ValidateArguments() && RunImpl(pfnProgress, pProgressData);
530✔
2842
}
2843

2844
/************************************************************************/
2845
/*                     GDALAlgorithm::Finalize()                        */
2846
/************************************************************************/
2847

2848
bool GDALAlgorithm::Finalize()
293✔
2849
{
2850
    bool ret = true;
293✔
2851
    if (m_selectedSubAlg)
293✔
2852
        ret = m_selectedSubAlg->Finalize();
29✔
2853

2854
    for (auto &arg : m_args)
4,744✔
2855
    {
2856
        if (arg->GetType() == GAAT_DATASET)
4,451✔
2857
        {
2858
            ret = arg->Get<GDALArgDatasetValue>().Close() && ret;
380✔
2859
        }
2860
        else if (arg->GetType() == GAAT_DATASET_LIST)
4,071✔
2861
        {
2862
            for (auto &ds : arg->Get<std::vector<GDALArgDatasetValue>>())
12✔
2863
            {
2864
                ret = ds.Close() && ret;
6✔
2865
            }
2866
        }
2867
    }
2868
    return ret;
293✔
2869
}
2870

2871
/************************************************************************/
2872
/*                   GDALAlgorithm::GetArgNamesForCLI()                 */
2873
/************************************************************************/
2874

2875
std::pair<std::vector<std::pair<GDALAlgorithmArg *, std::string>>, size_t>
2876
GDALAlgorithm::GetArgNamesForCLI() const
70✔
2877
{
2878
    std::vector<std::pair<GDALAlgorithmArg *, std::string>> options;
140✔
2879

2880
    size_t maxOptLen = 0;
70✔
2881
    for (const auto &arg : m_args)
623✔
2882
    {
2883
        if (arg->IsHiddenForCLI())
553✔
2884
            continue;
25✔
2885
        std::string opt;
528✔
2886
        bool addComma = false;
528✔
2887
        if (!arg->GetShortName().empty())
528✔
2888
        {
2889
            opt += '-';
125✔
2890
            opt += arg->GetShortName();
125✔
2891
            addComma = true;
125✔
2892
        }
2893
        for (const std::string &alias : arg->GetAliases())
563✔
2894
        {
2895
            if (addComma)
35✔
2896
                opt += ", ";
15✔
2897
            opt += "--";
35✔
2898
            opt += alias;
35✔
2899
            addComma = true;
35✔
2900
        }
2901
        if (!arg->GetName().empty())
528✔
2902
        {
2903
            if (addComma)
528✔
2904
                opt += ", ";
145✔
2905
            opt += "--";
528✔
2906
            opt += arg->GetName();
528✔
2907
        }
2908
        const auto &metaVar = arg->GetMetaVar();
528✔
2909
        if (!metaVar.empty())
528✔
2910
        {
2911
            opt += ' ';
207✔
2912
            if (metaVar.front() != '<')
207✔
2913
                opt += '<';
115✔
2914
            opt += metaVar;
207✔
2915
            if (metaVar.back() != '>')
207✔
2916
                opt += '>';
115✔
2917
        }
2918
        maxOptLen = std::max(maxOptLen, opt.size());
528✔
2919
        options.emplace_back(arg.get(), opt);
528✔
2920
    }
2921

2922
    return std::make_pair(std::move(options), maxOptLen);
140✔
2923
}
2924

2925
/************************************************************************/
2926
/*                    GDALAlgorithm::GetUsageForCLI()                   */
2927
/************************************************************************/
2928

2929
std::string
2930
GDALAlgorithm::GetUsageForCLI(bool shortUsage,
67✔
2931
                              const UsageOptions &usageOptions) const
2932
{
2933
    if (m_selectedSubAlg)
67✔
2934
        return m_selectedSubAlg->GetUsageForCLI(shortUsage, usageOptions);
4✔
2935

2936
    std::string osRet(usageOptions.isPipelineStep ? "*" : "Usage:");
126✔
2937
    std::string osPath;
126✔
2938
    for (const std::string &s : m_callPath)
91✔
2939
    {
2940
        if (!osPath.empty())
28✔
2941
            osPath += ' ';
3✔
2942
        osPath += s;
28✔
2943
    }
2944
    osRet += ' ';
63✔
2945
    osRet += osPath;
63✔
2946

2947
    bool hasNonPositionals = false;
63✔
2948
    for (const auto &arg : m_args)
571✔
2949
    {
2950
        if (!arg->IsHiddenForCLI() && !arg->IsPositional())
508✔
2951
            hasNonPositionals = true;
430✔
2952
    }
2953

2954
    if (HasSubAlgorithms())
63✔
2955
    {
2956
        if (m_callPath.size() == 1)
4✔
2957
        {
2958
            osRet += " <COMMAND>";
3✔
2959
            if (hasNonPositionals)
3✔
2960
                osRet += " [OPTIONS]";
3✔
2961
            osRet += "\nwhere <COMMAND> is one of:\n";
3✔
2962
        }
2963
        else
2964
        {
2965
            osRet += " <SUBCOMMAND>";
1✔
2966
            if (hasNonPositionals)
1✔
2967
                osRet += " [OPTIONS]";
1✔
2968
            osRet += "\nwhere <SUBCOMMAND> is one of:\n";
1✔
2969
        }
2970
        size_t maxNameLen = 0;
4✔
2971
        for (const auto &subAlgName : GetSubAlgorithmNames())
20✔
2972
        {
2973
            maxNameLen = std::max(maxNameLen, subAlgName.size());
16✔
2974
        }
2975
        for (const auto &subAlgName : GetSubAlgorithmNames())
20✔
2976
        {
2977
            auto subAlg = InstantiateSubAlgorithm(subAlgName);
32✔
2978
            assert(subAlg);
16✔
2979
            const std::string &name(subAlg->GetName());
16✔
2980
            osRet += "  - ";
16✔
2981
            osRet += name;
16✔
2982
            osRet += ": ";
16✔
2983
            osRet.append(maxNameLen - name.size(), ' ');
16✔
2984
            osRet += subAlg->GetDescription();
16✔
2985
            if (!subAlg->m_aliases.empty())
16✔
2986
            {
2987
                bool first = true;
×
2988
                for (const auto &alias : subAlg->GetAliases())
×
2989
                {
2990
                    if (alias == GDALAlgorithmRegistry::HIDDEN_ALIAS_SEPARATOR)
×
2991
                        break;
×
2992
                    if (first)
×
2993
                        osRet += " (alias: ";
×
2994
                    else
2995
                        osRet += ", ";
×
2996
                    osRet += alias;
×
2997
                    first = false;
×
2998
                }
2999
                if (!first)
×
3000
                {
3001
                    osRet += ')';
×
3002
                }
3003
            }
3004
            osRet += '\n';
16✔
3005
        }
3006

3007
        if (shortUsage && hasNonPositionals)
4✔
3008
        {
3009
            osRet += "\nTry '";
2✔
3010
            osRet += osPath;
2✔
3011
            osRet += " --help' for help.\n";
2✔
3012
        }
3013
    }
3014
    else
3015
    {
3016
        if (!m_args.empty())
59✔
3017
        {
3018
            if (hasNonPositionals)
59✔
3019
                osRet += " [OPTIONS]";
59✔
3020
            for (const auto *arg : m_positionalArgs)
92✔
3021
            {
3022
                const std::string &metavar = arg->GetMetaVar();
33✔
3023
                if (!metavar.empty() && metavar[0] == '<')
33✔
3024
                {
3025
                    osRet += metavar;
1✔
3026
                }
3027
                else
3028
                {
3029
                    osRet += " <";
32✔
3030
                    osRet += metavar;
32✔
3031
                    osRet += '>';
32✔
3032
                }
3033
            }
3034
        }
3035

3036
        const size_t nLenFirstLine = osRet.size();
59✔
3037
        osRet += '\n';
59✔
3038
        if (usageOptions.isPipelineStep)
59✔
3039
        {
3040
            osRet.append(nLenFirstLine, '-');
13✔
3041
            osRet += '\n';
13✔
3042
        }
3043

3044
        if (shortUsage)
59✔
3045
        {
3046
            osRet += "Try '";
4✔
3047
            osRet += osPath;
4✔
3048
            osRet += " --help' for help.\n";
4✔
3049
            return osRet;
4✔
3050
        }
3051

3052
        osRet += '\n';
55✔
3053
        osRet += m_description;
55✔
3054
        osRet += '\n';
55✔
3055
    }
3056

3057
    if (!m_args.empty() && !shortUsage)
59✔
3058
    {
3059
        std::vector<std::pair<GDALAlgorithmArg *, std::string>> options;
114✔
3060
        size_t maxOptLen;
3061
        std::tie(options, maxOptLen) = GetArgNamesForCLI();
57✔
3062
        if (usageOptions.maxOptLen)
57✔
3063
            maxOptLen = usageOptions.maxOptLen;
13✔
3064

3065
        const auto OutputArg =
3066
            [this, maxOptLen, &osRet](const GDALAlgorithmArg *arg,
343✔
3067
                                      const std::string &opt)
2,355✔
3068
        {
3069
            osRet += "  ";
343✔
3070
            osRet += opt;
343✔
3071
            osRet += "  ";
343✔
3072
            osRet.append(maxOptLen - opt.size(), ' ');
343✔
3073
            osRet += arg->GetDescription();
343✔
3074

3075
            const auto &choices = arg->GetChoices();
343✔
3076
            if (!choices.empty())
343✔
3077
            {
3078
                osRet += ". ";
6✔
3079
                osRet += arg->GetMetaVar();
6✔
3080
                osRet += '=';
6✔
3081
                bool firstChoice = true;
6✔
3082
                for (const auto &choice : choices)
35✔
3083
                {
3084
                    if (!firstChoice)
29✔
3085
                        osRet += '|';
23✔
3086
                    osRet += choice;
29✔
3087
                    firstChoice = false;
29✔
3088
                }
3089
            }
3090

3091
            if (arg->GetType() == GAAT_DATASET)
343✔
3092
            {
3093
                auto &val = arg->Get<GDALArgDatasetValue>();
9✔
3094
                if (val.GetInputFlags() == GADV_NAME &&
10✔
3095
                    val.GetOutputFlags() == GADV_OBJECT)
1✔
3096
                {
3097
                    osRet += " (created by algorithm)";
1✔
3098
                }
3099
            }
3100

3101
            if (arg->GetType() == GAAT_STRING && arg->HasDefaultValue())
343✔
3102
            {
3103
                osRet += " (default: ";
5✔
3104
                osRet += arg->GetDefault<std::string>();
5✔
3105
                osRet += ')';
5✔
3106
            }
3107
            else if (arg->GetType() == GAAT_BOOLEAN && arg->HasDefaultValue())
338✔
3108
            {
3109
                if (arg->GetDefault<bool>())
5✔
3110
                    osRet += " (default: true)";
×
3111
            }
3112
            else if (arg->GetType() == GAAT_INTEGER && arg->HasDefaultValue())
333✔
3113
            {
3114
                osRet += " (default: ";
1✔
3115
                osRet += CPLSPrintf("%d", arg->GetDefault<int>());
1✔
3116
                osRet += ')';
1✔
3117
            }
3118
            else if (arg->GetType() == GAAT_REAL && arg->HasDefaultValue())
332✔
3119
            {
3120
                osRet += " (default: ";
1✔
3121
                osRet += CPLSPrintf("%g", arg->GetDefault<double>());
1✔
3122
                osRet += ')';
1✔
3123
            }
3124

3125
            if (arg->GetDisplayHintAboutRepetition())
343✔
3126
            {
3127
                if (arg->GetMinCount() > 0 &&
340✔
3128
                    arg->GetMinCount() == arg->GetMaxCount())
6✔
3129
                {
3130
                    osRet += CPLSPrintf(" [%d values]", arg->GetMaxCount());
2✔
3131
                }
3132
                else if (arg->GetMinCount() > 0 &&
336✔
3133
                         arg->GetMaxCount() < GDALAlgorithmArgDecl::UNBOUNDED)
4✔
3134
                {
3135
                    osRet += CPLSPrintf(" [%d..%d values]", arg->GetMinCount(),
3136
                                        arg->GetMaxCount());
4✔
3137
                }
3138
                else if (arg->GetMinCount() > 0)
328✔
3139
                {
3140
                    osRet += CPLSPrintf(" [%d.. values]", arg->GetMinCount());
×
3141
                }
3142
                else if (arg->GetMaxCount() > 1)
328✔
3143
                {
3144
                    osRet += " [may be repeated]";
69✔
3145
                }
3146
            }
3147

3148
            if (arg->IsRequired())
343✔
3149
            {
3150
                osRet += " [required]";
17✔
3151
            }
3152

3153
            osRet += '\n';
343✔
3154

3155
            const auto &mutualExclusionGroup = arg->GetMutualExclusionGroup();
343✔
3156
            if (!mutualExclusionGroup.empty())
343✔
3157
            {
3158
                std::string otherArgs;
34✔
3159
                for (const auto &otherArg : m_args)
221✔
3160
                {
3161
                    if (otherArg->IsHiddenForCLI() || otherArg.get() == arg)
204✔
3162
                        continue;
21✔
3163
                    if (otherArg->GetMutualExclusionGroup() ==
183✔
3164
                        mutualExclusionGroup)
3165
                    {
3166
                        if (!otherArgs.empty())
22✔
3167
                            otherArgs += ", ";
6✔
3168
                        otherArgs += "--";
22✔
3169
                        otherArgs += otherArg->GetName();
22✔
3170
                    }
3171
                }
3172
                if (!otherArgs.empty())
17✔
3173
                {
3174
                    osRet += "  ";
16✔
3175
                    osRet += "  ";
16✔
3176
                    osRet.append(maxOptLen, ' ');
16✔
3177
                    osRet += "Mutually exclusive with ";
16✔
3178
                    osRet += otherArgs;
16✔
3179
                    osRet += '\n';
16✔
3180
                }
3181
            }
3182
        };
343✔
3183

3184
        if (!m_positionalArgs.empty())
57✔
3185
        {
3186
            osRet += "\nPositional arguments:\n";
21✔
3187
            for (const auto &[arg, opt] : options)
194✔
3188
            {
3189
                if (arg->IsPositional())
173✔
3190
                    OutputArg(arg, opt);
28✔
3191
            }
3192
        }
3193

3194
        if (hasNonPositionals)
57✔
3195
        {
3196
            bool hasCommon = false;
57✔
3197
            bool hasBase = false;
57✔
3198
            bool hasAdvanced = false;
57✔
3199
            bool hasEsoteric = false;
57✔
3200
            std::vector<std::string> categories;
114✔
3201
            for (const auto &iter : options)
465✔
3202
            {
3203
                const auto &arg = iter.first;
408✔
3204
                if (!arg->IsPositional())
408✔
3205
                {
3206
                    const auto &category = arg->GetCategory();
380✔
3207
                    if (category == GAAC_COMMON)
380✔
3208
                    {
3209
                        hasCommon = true;
291✔
3210
                    }
3211
                    else if (category == GAAC_BASE)
89✔
3212
                    {
3213
                        hasBase = true;
71✔
3214
                    }
3215
                    else if (category == GAAC_ADVANCED)
18✔
3216
                    {
3217
                        hasAdvanced = true;
14✔
3218
                    }
3219
                    else if (category == GAAC_ESOTERIC)
4✔
3220
                    {
3221
                        hasEsoteric = true;
3✔
3222
                    }
3223
                    else if (std::find(categories.begin(), categories.end(),
1✔
3224
                                       category) == categories.end())
1✔
3225
                    {
3226
                        categories.push_back(category);
1✔
3227
                    }
3228
                }
3229
            }
3230
            if (hasAdvanced)
57✔
3231
                categories.insert(categories.begin(), GAAC_ADVANCED);
4✔
3232
            if (hasBase)
57✔
3233
                categories.insert(categories.begin(), GAAC_BASE);
32✔
3234
            if (hasCommon && !usageOptions.isPipelineStep)
57✔
3235
                categories.insert(categories.begin(), GAAC_COMMON);
44✔
3236
            if (hasEsoteric)
57✔
3237
                categories.push_back(GAAC_ESOTERIC);
1✔
3238

3239
            for (const auto &category : categories)
139✔
3240
            {
3241
                osRet += "\n";
82✔
3242
                if (category != GAAC_BASE)
82✔
3243
                {
3244
                    osRet += category;
50✔
3245
                    osRet += ' ';
50✔
3246
                }
3247
                osRet += "Options:\n";
82✔
3248
                for (const auto &[arg, opt] : options)
697✔
3249
                {
3250
                    if (!arg->IsPositional() && arg->GetCategory() == category)
615✔
3251
                        OutputArg(arg, opt);
315✔
3252
                }
3253
            }
3254
        }
3255
    }
3256

3257
    if (!m_longDescription.empty())
59✔
3258
    {
3259
        osRet += '\n';
5✔
3260
        osRet += m_longDescription;
5✔
3261
        osRet += '\n';
5✔
3262
    }
3263

3264
    if (!m_helpURL.empty())
59✔
3265
    {
3266
        osRet += "\nFor more details, consult ";
59✔
3267
        osRet += GetHelpFullURL();
59✔
3268
        osRet += '\n';
59✔
3269
    }
3270

3271
    if (!m_callPath.empty() && m_callPath[0] == "gdal")
59✔
3272
    {
3273
        osRet += "\nWARNING: the gdal command is provisionally provided as an "
3274
                 "alternative interface to GDAL and OGR command line "
3275
                 "utilities.\nThe project reserves the right to modify, "
3276
                 "rename, reorganize, and change the behavior of the utility\n"
3277
                 "until it is officially frozen in a future feature release of "
3278
                 "GDAL.\n";
×
3279
    }
3280

3281
    return osRet;
59✔
3282
}
3283

3284
/************************************************************************/
3285
/*                    GDALAlgorithm::GetUsageAsJSON()                   */
3286
/************************************************************************/
3287

3288
std::string GDALAlgorithm::GetUsageAsJSON() const
97✔
3289
{
3290
    CPLJSONDocument oDoc;
194✔
3291
    auto oRoot = oDoc.GetRoot();
194✔
3292

3293
    if (m_displayInJSONUsage)
97✔
3294
    {
3295
        oRoot.Add("name", m_name);
95✔
3296
        CPLJSONArray jFullPath;
95✔
3297
        for (const std::string &s : m_callPath)
195✔
3298
        {
3299
            jFullPath.Add(s);
100✔
3300
        }
3301
        oRoot.Add("full_path", jFullPath);
95✔
3302
    }
3303

3304
    oRoot.Add("description", m_description);
97✔
3305
    if (!m_helpURL.empty())
97✔
3306
    {
3307
        oRoot.Add("short_url", m_helpURL);
97✔
3308
        oRoot.Add("url", GetHelpFullURL());
97✔
3309
    }
3310

3311
    CPLJSONArray jSubAlgorithms;
194✔
3312
    for (const auto &subAlgName : GetSubAlgorithmNames())
139✔
3313
    {
3314
        auto subAlg = InstantiateSubAlgorithm(subAlgName);
84✔
3315
        assert(subAlg);
42✔
3316
        if (subAlg->m_displayInJSONUsage)
42✔
3317
        {
3318
            CPLJSONDocument oSubDoc;
39✔
3319
            CPL_IGNORE_RET_VAL(oSubDoc.LoadMemory(subAlg->GetUsageAsJSON()));
39✔
3320
            jSubAlgorithms.Add(oSubDoc.GetRoot());
39✔
3321
        }
3322
    }
3323
    oRoot.Add("sub_algorithms", jSubAlgorithms);
97✔
3324

3325
    const auto ProcessArg = [](const GDALAlgorithmArg *arg)
675✔
3326
    {
3327
        CPLJSONObject jArg;
675✔
3328
        jArg.Add("name", arg->GetName());
675✔
3329
        jArg.Add("type", GDALAlgorithmArgTypeName(arg->GetType()));
675✔
3330
        jArg.Add("description", arg->GetDescription());
675✔
3331
        const auto &choices = arg->GetChoices();
675✔
3332
        if (!choices.empty())
675✔
3333
        {
3334
            CPLJSONArray jChoices;
19✔
3335
            for (const auto &choice : choices)
188✔
3336
                jChoices.Add(choice);
169✔
3337
            jArg.Add("choices", jChoices);
19✔
3338
        }
3339
        if (arg->HasDefaultValue())
675✔
3340
        {
3341
            switch (arg->GetType())
104✔
3342
            {
3343
                case GAAT_BOOLEAN:
79✔
3344
                    jArg.Add("default", arg->GetDefault<bool>());
79✔
3345
                    break;
79✔
3346
                case GAAT_STRING:
21✔
3347
                    jArg.Add("default", arg->GetDefault<std::string>());
21✔
3348
                    break;
21✔
3349
                case GAAT_INTEGER:
3✔
3350
                    jArg.Add("default", arg->GetDefault<int>());
3✔
3351
                    break;
3✔
3352
                case GAAT_REAL:
1✔
3353
                    jArg.Add("default", arg->GetDefault<double>());
1✔
3354
                    break;
1✔
3355
                case GAAT_DATASET:
×
3356
                case GAAT_STRING_LIST:
3357
                case GAAT_INTEGER_LIST:
3358
                case GAAT_REAL_LIST:
3359
                case GAAT_DATASET_LIST:
3360
                    CPLError(CE_Warning, CPLE_AppDefined,
×
3361
                             "Unhandled default value for arg %s",
3362
                             arg->GetName().c_str());
×
3363
                    break;
×
3364
            }
3365
        }
3366
        jArg.Add("required", arg->IsRequired());
675✔
3367
        if (GDALAlgorithmArgTypeIsList(arg->GetType()))
675✔
3368
        {
3369
            jArg.Add("packed_values_allowed", arg->GetPackedValuesAllowed());
242✔
3370
            jArg.Add("repeated_arg_allowed", arg->GetRepeatedArgAllowed());
242✔
3371
            jArg.Add("min_count", arg->GetMinCount());
242✔
3372
            jArg.Add("max_count", arg->GetMaxCount());
242✔
3373
        }
3374
        jArg.Add("category", arg->GetCategory());
675✔
3375

3376
        if (arg->GetType() == GAAT_DATASET)
675✔
3377
        {
3378
            const auto &val = arg->Get<GDALArgDatasetValue>();
91✔
3379
            {
3380
                CPLJSONArray jAr;
91✔
3381
                if (val.GetType() & GDAL_OF_RASTER)
91✔
3382
                    jAr.Add("raster");
65✔
3383
                if (val.GetType() & GDAL_OF_VECTOR)
91✔
3384
                    jAr.Add("vector");
32✔
3385
                if (val.GetType() & GDAL_OF_MULTIDIM_RASTER)
91✔
3386
                    jAr.Add("muldim_raster");
2✔
3387
                jArg.Add("dataset_type", jAr);
91✔
3388
            }
3389

3390
            const auto GetFlags = [](int flags)
129✔
3391
            {
3392
                CPLJSONArray jAr;
129✔
3393
                if (flags & GADV_NAME)
129✔
3394
                    jAr.Add("name");
91✔
3395
                if (flags & GADV_OBJECT)
129✔
3396
                    jAr.Add("dataset");
118✔
3397
                return jAr;
129✔
3398
            };
3399

3400
            if (arg->IsInput())
91✔
3401
            {
3402
                jArg.Add("input_flags", GetFlags(val.GetInputFlags()));
91✔
3403
            }
3404
            if (arg->IsOutput())
91✔
3405
            {
3406
                jArg.Add("output_flags", GetFlags(val.GetOutputFlags()));
38✔
3407
            }
3408
        }
3409

3410
        const auto &mutualExclusionGroup = arg->GetMutualExclusionGroup();
675✔
3411
        if (!mutualExclusionGroup.empty())
675✔
3412
        {
3413
            jArg.Add("mutual_exclusion_group", mutualExclusionGroup);
80✔
3414
        }
3415

3416
        const auto &metadata = arg->GetMetadata();
1,350✔
3417
        if (!metadata.empty())
675✔
3418
        {
3419
            CPLJSONObject jMetadata;
67✔
3420
            for (const auto &[key, values] : metadata)
134✔
3421
            {
3422
                CPLJSONArray jValue;
134✔
3423
                for (const auto &value : values)
166✔
3424
                    jValue.Add(value);
99✔
3425
                jMetadata.Add(key, jValue);
67✔
3426
            }
3427
            jArg.Add("metadata", jMetadata);
67✔
3428
        }
3429

3430
        return jArg;
1,350✔
3431
    };
3432

3433
    {
3434
        CPLJSONArray jArgs;
97✔
3435
        for (const auto &arg : m_args)
1,292✔
3436
        {
3437
            if (!arg->IsOnlyForCLI() && arg->IsInput() && !arg->IsOutput())
1,195✔
3438
                jArgs.Add(ProcessArg(arg.get()));
634✔
3439
        }
3440
        oRoot.Add("input_arguments", jArgs);
97✔
3441
    }
3442

3443
    {
3444
        CPLJSONArray jArgs;
97✔
3445
        for (const auto &arg : m_args)
1,292✔
3446
        {
3447
            if (!arg->IsOnlyForCLI() && !arg->IsInput() && arg->IsOutput())
1,195✔
3448
                jArgs.Add(ProcessArg(arg.get()));
3✔
3449
        }
3450
        oRoot.Add("output_arguments", jArgs);
97✔
3451
    }
3452

3453
    {
3454
        CPLJSONArray jArgs;
97✔
3455
        for (const auto &arg : m_args)
1,292✔
3456
        {
3457
            if (!arg->IsOnlyForCLI() && arg->IsInput() && arg->IsOutput())
1,195✔
3458
                jArgs.Add(ProcessArg(arg.get()));
38✔
3459
        }
3460
        oRoot.Add("input_output_arguments", jArgs);
97✔
3461
    }
3462

3463
    return oDoc.SaveAsString();
194✔
3464
}
3465

3466
/************************************************************************/
3467
/*                    GDALAlgorithm::GetAutoComplete()                  */
3468
/************************************************************************/
3469

3470
std::vector<std::string>
3471
GDALAlgorithm::GetAutoComplete(std::vector<std::string> &args,
43✔
3472
                               bool showAllOptions)
3473
{
3474
    std::vector<std::string> ret;
43✔
3475

3476
    std::string option;
86✔
3477
    std::string value;
86✔
3478
    ExtractLastOptionAndValue(args, option, value);
43✔
3479

3480
    if (option.empty() && !args.empty() && !args.back().empty() &&
51✔
3481
        args.back()[0] == '-')
8✔
3482
    {
3483
        // List available options
3484
        for (const auto &arg : GetArgs())
90✔
3485
        {
3486
            if (arg->IsHiddenForCLI() ||
164✔
3487
                (!showAllOptions &&
157✔
3488
                 (arg->GetName() == "help" || arg->GetName() == "drivers" ||
210✔
3489
                  arg->GetName() == "config" || arg->GetName() == "version" ||
174✔
3490
                  arg->GetName() == "json-usage")))
52✔
3491
            {
3492
                continue;
32✔
3493
            }
3494
            if (!arg->GetShortName().empty())
51✔
3495
            {
3496
                ret.push_back(std::string("-").append(arg->GetShortName()));
14✔
3497
            }
3498
            for (const std::string &alias : arg->GetAliases())
68✔
3499
            {
3500
                ret.push_back(std::string("--").append(alias));
17✔
3501
            }
3502
            if (!arg->GetName().empty())
51✔
3503
            {
3504
                ret.push_back(std::string("--").append(arg->GetName()));
51✔
3505
            }
3506
        }
3507
    }
3508
    else if (!option.empty())
36✔
3509
    {
3510
        // List possible choices for current option
3511
        auto arg = GetArg(option);
33✔
3512
        if (arg && arg->GetType() != GAAT_BOOLEAN)
33✔
3513
        {
3514
            ret = arg->GetChoices();
33✔
3515
            if (ret.empty())
33✔
3516
            {
3517
                {
3518
                    CPLErrorStateBackuper oErrorQuieter(CPLQuietErrorHandler);
29✔
3519
                    SetParseForAutoCompletion();
29✔
3520
                    CPL_IGNORE_RET_VAL(ParseCommandLineArguments(args));
29✔
3521
                }
3522
                ret = arg->GetAutoCompleteChoices(value);
29✔
3523
            }
3524
            if (ret.empty())
33✔
3525
            {
3526
                ret.push_back("**");
1✔
3527
                ret.push_back(
1✔
3528
                    std::string("description: ").append(arg->GetDescription()));
1✔
3529
            }
3530
        }
3531
    }
3532
    else if (!args.empty() && STARTS_WITH(args.back().c_str(), "/vsi"))
3✔
3533
    {
3534
        auto arg = GetArg(GDAL_ARG_NAME_INPUT);
1✔
3535
        if (arg)
1✔
3536
        {
3537
            ret = arg->GetAutoCompleteChoices(args.back());
1✔
3538
        }
3539
    }
3540
    else
3541
    {
3542
        // List possible sub-algorithms
3543
        ret = GetSubAlgorithmNames();
2✔
3544
    }
3545

3546
    return ret;
86✔
3547
}
3548

3549
/************************************************************************/
3550
/*             GDALAlgorithm::ExtractLastOptionAndValue()               */
3551
/************************************************************************/
3552

3553
void GDALAlgorithm::ExtractLastOptionAndValue(std::vector<std::string> &args,
43✔
3554
                                              std::string &option,
3555
                                              std::string &value) const
3556
{
3557
    if (!args.empty() && !args.back().empty() && args.back()[0] == '-')
43✔
3558
    {
3559
        const auto nPosEqual = args.back().find('=');
28✔
3560
        if (nPosEqual == std::string::npos)
28✔
3561
        {
3562
            // Deal with "gdal ... --option"
3563
            if (GetArg(args.back()))
17✔
3564
            {
3565
                option = args.back();
10✔
3566
                args.pop_back();
10✔
3567
            }
3568
        }
3569
        else
3570
        {
3571
            // Deal with "gdal ... --option=<value>"
3572
            if (GetArg(args.back().substr(0, nPosEqual)))
11✔
3573
            {
3574
                option = args.back().substr(0, nPosEqual);
11✔
3575
                value = args.back().substr(nPosEqual + 1);
11✔
3576
                args.pop_back();
11✔
3577
            }
3578
        }
3579
    }
3580
    else if (args.size() >= 2 && !args[args.size() - 2].empty() &&
27✔
3581
             args[args.size() - 2][0] == '-')
12✔
3582
    {
3583
        // Deal with "gdal ... --option <value>"
3584
        auto arg = GetArg(args[args.size() - 2]);
12✔
3585
        if (arg && arg->GetType() != GAAT_BOOLEAN)
12✔
3586
        {
3587
            option = args[args.size() - 2];
12✔
3588
            value = args.back();
12✔
3589
            args.pop_back();
12✔
3590
        }
3591
    }
3592

3593
    const auto IsKeyValueOption = [](const std::string &osStr)
43✔
3594
    {
3595
        return osStr == "--co" || osStr == "--creation-option" ||
100✔
3596
               osStr == "--lco" || osStr == "--layer-creation-option" ||
81✔
3597
               osStr == "--oo" || osStr == "--open-option";
98✔
3598
    };
3599

3600
    if (IsKeyValueOption(option))
43✔
3601
    {
3602
        const auto nPosEqual = value.find('=');
19✔
3603
        if (nPosEqual != std::string::npos)
19✔
3604
        {
3605
            value.resize(nPosEqual);
10✔
3606
        }
3607
    }
3608
}
43✔
3609

3610
/************************************************************************/
3611
/*                        GDALAlgorithmRelease()                        */
3612
/************************************************************************/
3613

3614
/** Release a handle to an algorithm.
3615
 *
3616
 * @since 3.11
3617
 */
3618
void GDALAlgorithmRelease(GDALAlgorithmH hAlg)
692✔
3619
{
3620
    delete hAlg;
692✔
3621
}
692✔
3622

3623
/************************************************************************/
3624
/*                        GDALAlgorithmGetName()                        */
3625
/************************************************************************/
3626

3627
/** Return the algorithm name.
3628
 *
3629
 * @param hAlg Handle to an algorithm. Must NOT be null.
3630
 * @return algorithm name whose lifetime is bound to hAlg and which must not
3631
 * be freed.
3632
 * @since 3.11
3633
 */
3634
const char *GDALAlgorithmGetName(GDALAlgorithmH hAlg)
2✔
3635
{
3636
    VALIDATE_POINTER1(hAlg, __func__, nullptr);
2✔
3637
    return hAlg->ptr->GetName().c_str();
2✔
3638
}
3639

3640
/************************************************************************/
3641
/*                     GDALAlgorithmGetDescription()                    */
3642
/************************************************************************/
3643

3644
/** Return the algorithm (short) description.
3645
 *
3646
 * @param hAlg Handle to an algorithm. Must NOT be null.
3647
 * @return algorithm description whose lifetime is bound to hAlg and which must
3648
 * not be freed.
3649
 * @since 3.11
3650
 */
3651
const char *GDALAlgorithmGetDescription(GDALAlgorithmH hAlg)
2✔
3652
{
3653
    VALIDATE_POINTER1(hAlg, __func__, nullptr);
2✔
3654
    return hAlg->ptr->GetDescription().c_str();
2✔
3655
}
3656

3657
/************************************************************************/
3658
/*                     GDALAlgorithmGetLongDescription()                */
3659
/************************************************************************/
3660

3661
/** Return the algorithm (longer) description.
3662
 *
3663
 * @param hAlg Handle to an algorithm. Must NOT be null.
3664
 * @return algorithm description whose lifetime is bound to hAlg and which must
3665
 * not be freed.
3666
 * @since 3.11
3667
 */
3668
const char *GDALAlgorithmGetLongDescription(GDALAlgorithmH hAlg)
2✔
3669
{
3670
    VALIDATE_POINTER1(hAlg, __func__, nullptr);
2✔
3671
    return hAlg->ptr->GetLongDescription().c_str();
2✔
3672
}
3673

3674
/************************************************************************/
3675
/*                     GDALAlgorithmGetHelpFullURL()                    */
3676
/************************************************************************/
3677

3678
/** Return the algorithm full URL.
3679
 *
3680
 * @param hAlg Handle to an algorithm. Must NOT be null.
3681
 * @return algorithm URL whose lifetime is bound to hAlg and which must
3682
 * not be freed.
3683
 * @since 3.11
3684
 */
3685
const char *GDALAlgorithmGetHelpFullURL(GDALAlgorithmH hAlg)
2✔
3686
{
3687
    VALIDATE_POINTER1(hAlg, __func__, nullptr);
2✔
3688
    return hAlg->ptr->GetHelpFullURL().c_str();
2✔
3689
}
3690

3691
/************************************************************************/
3692
/*                     GDALAlgorithmHasSubAlgorithms()                  */
3693
/************************************************************************/
3694

3695
/** Return whether the algorithm has sub-algorithms.
3696
 *
3697
 * @param hAlg Handle to an algorithm. Must NOT be null.
3698
 * @since 3.11
3699
 */
3700
bool GDALAlgorithmHasSubAlgorithms(GDALAlgorithmH hAlg)
304✔
3701
{
3702
    VALIDATE_POINTER1(hAlg, __func__, false);
304✔
3703
    return hAlg->ptr->HasSubAlgorithms();
304✔
3704
}
3705

3706
/************************************************************************/
3707
/*                 GDALAlgorithmGetSubAlgorithmNames()                  */
3708
/************************************************************************/
3709

3710
/** Get the names of registered algorithms.
3711
 *
3712
 * @param hAlg Handle to an algorithm. Must NOT be null.
3713
 * @return a NULL terminated list of names, which must be destroyed with
3714
 * CSLDestroy()
3715
 * @since 3.11
3716
 */
3717
char **GDALAlgorithmGetSubAlgorithmNames(GDALAlgorithmH hAlg)
2✔
3718
{
3719
    VALIDATE_POINTER1(hAlg, __func__, nullptr);
2✔
3720
    return CPLStringList(hAlg->ptr->GetSubAlgorithmNames()).StealList();
2✔
3721
}
3722

3723
/************************************************************************/
3724
/*                GDALAlgorithmInstantiateSubAlgorithm()                */
3725
/************************************************************************/
3726

3727
/** Instantiate an algorithm by its name (or its alias).
3728
 *
3729
 * @param hAlg Handle to an algorithm. Must NOT be null.
3730
 * @param pszSubAlgName Algorithm name. Must NOT be null.
3731
 * @return an handle to the algorithm (to be freed with GDALAlgorithmRelease),
3732
 * or NULL if the algorithm does not exist or another error occurred.
3733
 * @since 3.11
3734
 */
3735
GDALAlgorithmH GDALAlgorithmInstantiateSubAlgorithm(GDALAlgorithmH hAlg,
310✔
3736
                                                    const char *pszSubAlgName)
3737
{
3738
    VALIDATE_POINTER1(hAlg, __func__, nullptr);
310✔
3739
    VALIDATE_POINTER1(pszSubAlgName, __func__, nullptr);
310✔
3740
    auto subAlg = hAlg->ptr->InstantiateSubAlgorithm(pszSubAlgName);
620✔
3741
    return subAlg
3742
               ? std::make_unique<GDALAlgorithmHS>(std::move(subAlg)).release()
620✔
3743
               : nullptr;
620✔
3744
}
3745

3746
/************************************************************************/
3747
/*                GDALAlgorithmParseCommandLineArguments()              */
3748
/************************************************************************/
3749

3750
/** Parse a command line argument, which does not include the algorithm
3751
 * name, to set the value of corresponding arguments.
3752
 *
3753
 * @param hAlg Handle to an algorithm. Must NOT be null.
3754
 * @param papszArgs NULL-terminated list of arguments, not including the algorithm name.
3755
 * @return true if successful, false otherwise
3756
 * @since 3.11
3757
 */
3758

3759
bool GDALAlgorithmParseCommandLineArguments(GDALAlgorithmH hAlg,
241✔
3760
                                            CSLConstList papszArgs)
3761
{
3762
    VALIDATE_POINTER1(hAlg, __func__, false);
241✔
3763
    return hAlg->ptr->ParseCommandLineArguments(CPLStringList(papszArgs));
241✔
3764
}
3765

3766
/************************************************************************/
3767
/*                  GDALAlgorithmGetActualAlgorithm()                   */
3768
/************************************************************************/
3769

3770
/** Return the actual algorithm that is going to be invoked, when the
3771
 * current algorithm has sub-algorithms.
3772
 *
3773
 * Only valid after GDALAlgorithmParseCommandLineArguments() has been called.
3774
 *
3775
 * Note that the lifetime of the returned algorithm does not exceed the one of
3776
 * the hAlg instance that owns it.
3777
 *
3778
 * @param hAlg Handle to an algorithm. Must NOT be null.
3779
 * @return an handle to the algorithm (to be freed with GDALAlgorithmRelease).
3780
 * @since 3.11
3781
 */
3782
GDALAlgorithmH GDALAlgorithmGetActualAlgorithm(GDALAlgorithmH hAlg)
65✔
3783
{
3784
    VALIDATE_POINTER1(hAlg, __func__, nullptr);
65✔
3785
    return GDALAlgorithmHS::FromRef(hAlg->ptr->GetActualAlgorithm()).release();
65✔
3786
}
3787

3788
/************************************************************************/
3789
/*                          GDALAlgorithmRun()                          */
3790
/************************************************************************/
3791

3792
/** Execute the algorithm, starting with ValidateArguments() and then
3793
 * calling RunImpl().
3794
 *
3795
 * @param hAlg Handle to an algorithm. Must NOT be null.
3796
 * @param pfnProgress Progress callback. May be null.
3797
 * @param pProgressData Progress callback user data. May be null.
3798
 * @return true if successful, false otherwise
3799
 * @since 3.11
3800
 */
3801

3802
bool GDALAlgorithmRun(GDALAlgorithmH hAlg, GDALProgressFunc pfnProgress,
285✔
3803
                      void *pProgressData)
3804
{
3805
    VALIDATE_POINTER1(hAlg, __func__, false);
285✔
3806
    return hAlg->ptr->Run(pfnProgress, pProgressData);
285✔
3807
}
3808

3809
/************************************************************************/
3810
/*                       GDALAlgorithmFinalize()                        */
3811
/************************************************************************/
3812

3813
/** Complete any pending actions, and return the final status.
3814
 * This is typically useful for algorithm that generate an output dataset.
3815
 *
3816
 * Note that this function does *NOT* release memory associated with the
3817
 * algorithm. GDALAlgorithmRelease() must still be called afterwards.
3818
 *
3819
 * @param hAlg Handle to an algorithm. Must NOT be null.
3820
 * @return true if successful, false otherwise
3821
 * @since 3.11
3822
 */
3823

3824
bool GDALAlgorithmFinalize(GDALAlgorithmH hAlg)
147✔
3825
{
3826
    VALIDATE_POINTER1(hAlg, __func__, false);
147✔
3827
    return hAlg->ptr->Finalize();
147✔
3828
}
3829

3830
/************************************************************************/
3831
/*                    GDALAlgorithmGetUsageAsJSON()                     */
3832
/************************************************************************/
3833

3834
/** Return the usage of the algorithm as a JSON-serialized string.
3835
 *
3836
 * This can be used to dynamically generate interfaces to algorithms.
3837
 *
3838
 * @param hAlg Handle to an algorithm. Must NOT be null.
3839
 * @return a string that must be freed with CPLFree()
3840
 * @since 3.11
3841
 */
3842
char *GDALAlgorithmGetUsageAsJSON(GDALAlgorithmH hAlg)
4✔
3843
{
3844
    VALIDATE_POINTER1(hAlg, __func__, nullptr);
4✔
3845
    return CPLStrdup(hAlg->ptr->GetUsageAsJSON().c_str());
4✔
3846
}
3847

3848
/************************************************************************/
3849
/*                      GDALAlgorithmGetArgNames()                      */
3850
/************************************************************************/
3851

3852
/** Return the list of available argument names.
3853
 *
3854
 * @param hAlg Handle to an algorithm. Must NOT be null.
3855
 * @return a NULL terminated list of names, which must be destroyed with
3856
 * CSLDestroy()
3857
 * @since 3.11
3858
 */
3859
char **GDALAlgorithmGetArgNames(GDALAlgorithmH hAlg)
2✔
3860
{
3861
    VALIDATE_POINTER1(hAlg, __func__, nullptr);
2✔
3862
    CPLStringList list;
4✔
3863
    for (const auto &arg : hAlg->ptr->GetArgs())
29✔
3864
        list.AddString(arg->GetName().c_str());
27✔
3865
    return list.StealList();
2✔
3866
}
3867

3868
/************************************************************************/
3869
/*                        GDALAlgorithmGetArg()                         */
3870
/************************************************************************/
3871

3872
/** Return an argument from its name.
3873
 *
3874
 * The lifetime of the returned object does not exceed the one of hAlg.
3875
 *
3876
 * @param hAlg Handle to an algorithm. Must NOT be null.
3877
 * @param pszArgName Argument name. Must NOT be null.
3878
 * @return an argument that must be released with GDALAlgorithmArgRelease(),
3879
 * or nullptr in case of error
3880
 * @since 3.11
3881
 */
3882
GDALAlgorithmArgH GDALAlgorithmGetArg(GDALAlgorithmH hAlg,
326✔
3883
                                      const char *pszArgName)
3884
{
3885
    VALIDATE_POINTER1(hAlg, __func__, nullptr);
326✔
3886
    VALIDATE_POINTER1(pszArgName, __func__, nullptr);
326✔
3887
    auto arg = hAlg->ptr->GetArg(pszArgName);
326✔
3888
    if (!arg)
326✔
3889
        return nullptr;
2✔
3890
    return std::make_unique<GDALAlgorithmArgHS>(arg).release();
324✔
3891
}
3892

3893
/************************************************************************/
3894
/*                       GDALAlgorithmArgRelease()                      */
3895
/************************************************************************/
3896

3897
/** Release a handle to an argument.
3898
 *
3899
 * @since 3.11
3900
 */
3901
void GDALAlgorithmArgRelease(GDALAlgorithmArgH hArg)
324✔
3902
{
3903
    delete hArg;
324✔
3904
}
324✔
3905

3906
/************************************************************************/
3907
/*                      GDALAlgorithmArgGetName()                       */
3908
/************************************************************************/
3909

3910
/** Return the name of an argument.
3911
 *
3912
 * @param hArg Handle to an argument. Must NOT be null.
3913
 * @return argument name whose lifetime is bound to hArg and which must not
3914
 * be freed.
3915
 * @since 3.11
3916
 */
3917
const char *GDALAlgorithmArgGetName(GDALAlgorithmArgH hArg)
1✔
3918
{
3919
    VALIDATE_POINTER1(hArg, __func__, nullptr);
1✔
3920
    return hArg->ptr->GetName().c_str();
1✔
3921
}
3922

3923
/************************************************************************/
3924
/*                       GDALAlgorithmArgGetType()                      */
3925
/************************************************************************/
3926

3927
/** Get the type of an argument
3928
 *
3929
 * @param hArg Handle to an argument. Must NOT be null.
3930
 * @since 3.11
3931
 */
3932
GDALAlgorithmArgType GDALAlgorithmArgGetType(GDALAlgorithmArgH hArg)
316✔
3933
{
3934
    VALIDATE_POINTER1(hArg, __func__, GAAT_STRING);
316✔
3935
    return hArg->ptr->GetType();
316✔
3936
}
3937

3938
/************************************************************************/
3939
/*                   GDALAlgorithmArgGetDescription()                   */
3940
/************************************************************************/
3941

3942
/** Return the description of an argument.
3943
 *
3944
 * @param hArg Handle to an argument. Must NOT be null.
3945
 * @return argument descriptioin whose lifetime is bound to hArg and which must not
3946
 * be freed.
3947
 * @since 3.11
3948
 */
3949
const char *GDALAlgorithmArgGetDescription(GDALAlgorithmArgH hArg)
1✔
3950
{
3951
    VALIDATE_POINTER1(hArg, __func__, nullptr);
1✔
3952
    return hArg->ptr->GetDescription().c_str();
1✔
3953
}
3954

3955
/************************************************************************/
3956
/*                   GDALAlgorithmArgGetShortName()                     */
3957
/************************************************************************/
3958

3959
/** Return the short name, or empty string if there is none
3960
 *
3961
 * @param hArg Handle to an argument. Must NOT be null.
3962
 * @return short name whose lifetime is bound to hArg and which must not
3963
 * be freed.
3964
 * @since 3.11
3965
 */
3966
const char *GDALAlgorithmArgGetShortName(GDALAlgorithmArgH hArg)
1✔
3967
{
3968
    VALIDATE_POINTER1(hArg, __func__, nullptr);
1✔
3969
    return hArg->ptr->GetShortName().c_str();
1✔
3970
}
3971

3972
/************************************************************************/
3973
/*                    GDALAlgorithmArgGetAliases()                      */
3974
/************************************************************************/
3975

3976
/** Return the aliases (potentially none)
3977
 *
3978
 * @param hArg Handle to an argument. Must NOT be null.
3979
 * @return a NULL terminated list of names, which must be destroyed with
3980
 * CSLDestroy()
3981

3982
 * @since 3.11
3983
 */
3984
char **GDALAlgorithmArgGetAliases(GDALAlgorithmArgH hArg)
1✔
3985
{
3986
    VALIDATE_POINTER1(hArg, __func__, nullptr);
1✔
3987
    return CPLStringList(hArg->ptr->GetAliases()).StealList();
1✔
3988
}
3989

3990
/************************************************************************/
3991
/*                    GDALAlgorithmArgGetMetaVar()                      */
3992
/************************************************************************/
3993

3994
/** Return the "meta-var" hint.
3995
 *
3996
 * By default, the meta-var value is the long name of the argument in
3997
 * upper case.
3998
 *
3999
 * @param hArg Handle to an argument. Must NOT be null.
4000
 * @return meta-var hint whose lifetime is bound to hArg and which must not
4001
 * be freed.
4002
 * @since 3.11
4003
 */
4004
const char *GDALAlgorithmArgGetMetaVar(GDALAlgorithmArgH hArg)
1✔
4005
{
4006
    VALIDATE_POINTER1(hArg, __func__, nullptr);
1✔
4007
    return hArg->ptr->GetMetaVar().c_str();
1✔
4008
}
4009

4010
/************************************************************************/
4011
/*                   GDALAlgorithmArgGetCategory()                      */
4012
/************************************************************************/
4013

4014
/** Return the argument category
4015
 *
4016
 * GAAC_COMMON, GAAC_BASE, GAAC_ADVANCED, GAAC_ESOTERIC or a custom category.
4017
 *
4018
 * @param hArg Handle to an argument. Must NOT be null.
4019
 * @return category whose lifetime is bound to hArg and which must not
4020
 * be freed.
4021
 * @since 3.11
4022
 */
4023
const char *GDALAlgorithmArgGetCategory(GDALAlgorithmArgH hArg)
1✔
4024
{
4025
    VALIDATE_POINTER1(hArg, __func__, nullptr);
1✔
4026
    return hArg->ptr->GetCategory().c_str();
1✔
4027
}
4028

4029
/************************************************************************/
4030
/*                   GDALAlgorithmArgIsPositional()                     */
4031
/************************************************************************/
4032

4033
/** Return if the argument is a positional one.
4034
 *
4035
 * @param hArg Handle to an argument. Must NOT be null.
4036
 * @since 3.11
4037
 */
4038
bool GDALAlgorithmArgIsPositional(GDALAlgorithmArgH hArg)
1✔
4039
{
4040
    VALIDATE_POINTER1(hArg, __func__, false);
1✔
4041
    return hArg->ptr->IsPositional();
1✔
4042
}
4043

4044
/************************************************************************/
4045
/*                   GDALAlgorithmArgIsRequired()                       */
4046
/************************************************************************/
4047

4048
/** Return whether the argument is required. Defaults to false.
4049
 *
4050
 * @param hArg Handle to an argument. Must NOT be null.
4051
 * @since 3.11
4052
 */
4053
bool GDALAlgorithmArgIsRequired(GDALAlgorithmArgH hArg)
1✔
4054
{
4055
    VALIDATE_POINTER1(hArg, __func__, false);
1✔
4056
    return hArg->ptr->IsRequired();
1✔
4057
}
4058

4059
/************************************************************************/
4060
/*                   GDALAlgorithmArgGetMinCount()                      */
4061
/************************************************************************/
4062

4063
/** Return the minimum number of values for the argument.
4064
 *
4065
 * Defaults to 0.
4066
 * Only applies to list type of arguments.
4067
 *
4068
 * @param hArg Handle to an argument. Must NOT be null.
4069
 * @since 3.11
4070
 */
4071
int GDALAlgorithmArgGetMinCount(GDALAlgorithmArgH hArg)
1✔
4072
{
4073
    VALIDATE_POINTER1(hArg, __func__, 0);
1✔
4074
    return hArg->ptr->GetMinCount();
1✔
4075
}
4076

4077
/************************************************************************/
4078
/*                   GDALAlgorithmArgGetMaxCount()                      */
4079
/************************************************************************/
4080

4081
/** Return the maximum number of values for the argument.
4082
 *
4083
 * Defaults to 1 for scalar types, and INT_MAX for list types.
4084
 * Only applies to list type of arguments.
4085
 *
4086
 * @param hArg Handle to an argument. Must NOT be null.
4087
 * @since 3.11
4088
 */
4089
int GDALAlgorithmArgGetMaxCount(GDALAlgorithmArgH hArg)
1✔
4090
{
4091
    VALIDATE_POINTER1(hArg, __func__, 0);
1✔
4092
    return hArg->ptr->GetMaxCount();
1✔
4093
}
4094

4095
/************************************************************************/
4096
/*                GDALAlgorithmArgGetPackedValuesAllowed()              */
4097
/************************************************************************/
4098

4099
/** Return whether, for list type of arguments, several values, space
4100
 * separated, may be specified. That is "--foo=bar,baz".
4101
 * The default is true.
4102
 *
4103
 * @param hArg Handle to an argument. Must NOT be null.
4104
 * @since 3.11
4105
 */
4106
bool GDALAlgorithmArgGetPackedValuesAllowed(GDALAlgorithmArgH hArg)
1✔
4107
{
4108
    VALIDATE_POINTER1(hArg, __func__, false);
1✔
4109
    return hArg->ptr->GetPackedValuesAllowed();
1✔
4110
}
4111

4112
/************************************************************************/
4113
/*                GDALAlgorithmArgGetRepeatedArgAllowed()               */
4114
/************************************************************************/
4115

4116
/** Return whether, for list type of arguments, the argument may be
4117
 * repeated. That is "--foo=bar --foo=baz".
4118
 * The default is true.
4119
 *
4120
 * @param hArg Handle to an argument. Must NOT be null.
4121
 * @since 3.11
4122
 */
4123
bool GDALAlgorithmArgGetRepeatedArgAllowed(GDALAlgorithmArgH hArg)
1✔
4124
{
4125
    VALIDATE_POINTER1(hArg, __func__, false);
1✔
4126
    return hArg->ptr->GetRepeatedArgAllowed();
1✔
4127
}
4128

4129
/************************************************************************/
4130
/*                    GDALAlgorithmArgGetChoices()                      */
4131
/************************************************************************/
4132

4133
/** Return the allowed values (as strings) for the argument.
4134
 *
4135
 * Only honored for GAAT_STRING and GAAT_STRING_LIST types.
4136
 *
4137
 * @param hArg Handle to an argument. Must NOT be null.
4138
 * @return a NULL terminated list of names, which must be destroyed with
4139
 * CSLDestroy()
4140

4141
 * @since 3.11
4142
 */
4143
char **GDALAlgorithmArgGetChoices(GDALAlgorithmArgH hArg)
1✔
4144
{
4145
    VALIDATE_POINTER1(hArg, __func__, nullptr);
1✔
4146
    return CPLStringList(hArg->ptr->GetChoices()).StealList();
1✔
4147
}
4148

4149
/************************************************************************/
4150
/*                   GDALAlgorithmArgIsExplicitlySet()                  */
4151
/************************************************************************/
4152

4153
/** Return whether the argument value has been explicitly set with Set()
4154
 *
4155
 * @param hArg Handle to an argument. Must NOT be null.
4156
 * @since 3.11
4157
 */
4158
bool GDALAlgorithmArgIsExplicitlySet(GDALAlgorithmArgH hArg)
1✔
4159
{
4160
    VALIDATE_POINTER1(hArg, __func__, false);
1✔
4161
    return hArg->ptr->IsExplicitlySet();
1✔
4162
}
4163

4164
/************************************************************************/
4165
/*                   GDALAlgorithmArgHasDefaultValue()                  */
4166
/************************************************************************/
4167

4168
/** Return if the argument has a declared default value.
4169
 *
4170
 * @param hArg Handle to an argument. Must NOT be null.
4171
 * @since 3.11
4172
 */
4173
bool GDALAlgorithmArgHasDefaultValue(GDALAlgorithmArgH hArg)
1✔
4174
{
4175
    VALIDATE_POINTER1(hArg, __func__, false);
1✔
4176
    return hArg->ptr->HasDefaultValue();
1✔
4177
}
4178

4179
/************************************************************************/
4180
/*                   GDALAlgorithmArgIsHiddenForCLI()                   */
4181
/************************************************************************/
4182

4183
/** Return whether the argument must not be mentioned in CLI usage.
4184
 *
4185
 * For example, "output-value" for "gdal raster info", which is only
4186
 * meant when the algorithm is used from a non-CLI context.
4187
 *
4188
 * @param hArg Handle to an argument. Must NOT be null.
4189
 * @since 3.11
4190
 */
4191
bool GDALAlgorithmArgIsHiddenForCLI(GDALAlgorithmArgH hArg)
1✔
4192
{
4193
    VALIDATE_POINTER1(hArg, __func__, false);
1✔
4194
    return hArg->ptr->IsHiddenForCLI();
1✔
4195
}
4196

4197
/************************************************************************/
4198
/*                   GDALAlgorithmArgIsOnlyForCLI()                     */
4199
/************************************************************************/
4200

4201
/** Return whether the argument is only for CLI usage.
4202
 *
4203
 * For example "--help"
4204
 *
4205
 * @param hArg Handle to an argument. Must NOT be null.
4206
 * @since 3.11
4207
 */
4208
bool GDALAlgorithmArgIsOnlyForCLI(GDALAlgorithmArgH hArg)
1✔
4209
{
4210
    VALIDATE_POINTER1(hArg, __func__, false);
1✔
4211
    return hArg->ptr->IsOnlyForCLI();
1✔
4212
}
4213

4214
/************************************************************************/
4215
/*                     GDALAlgorithmArgIsInput()                        */
4216
/************************************************************************/
4217

4218
/** Indicate whether the value of the argument is read-only during the
4219
 * execution of the algorithm.
4220
 *
4221
 * Default is true.
4222
 *
4223
 * @param hArg Handle to an argument. Must NOT be null.
4224
 * @since 3.11
4225
 */
4226
bool GDALAlgorithmArgIsInput(GDALAlgorithmArgH hArg)
1✔
4227
{
4228
    VALIDATE_POINTER1(hArg, __func__, false);
1✔
4229
    return hArg->ptr->IsInput();
1✔
4230
}
4231

4232
/************************************************************************/
4233
/*                     GDALAlgorithmArgIsOutput()                       */
4234
/************************************************************************/
4235

4236
/** Return whether (at least part of) the value of the argument is set
4237
 * during the execution of the algorithm.
4238
 *
4239
 * For example, "output-value" for "gdal raster info"
4240
 * Default is false.
4241
 * An argument may return both IsInput() and IsOutput() as true.
4242
 * For example the "gdal raster convert" algorithm consumes the dataset
4243
 * name of its "output" argument, and sets the dataset object during its
4244
 * execution.
4245
 *
4246
 * @param hArg Handle to an argument. Must NOT be null.
4247
 * @since 3.11
4248
 */
4249
bool GDALAlgorithmArgIsOutput(GDALAlgorithmArgH hArg)
1✔
4250
{
4251
    VALIDATE_POINTER1(hArg, __func__, false);
1✔
4252
    return hArg->ptr->IsOutput();
1✔
4253
}
4254

4255
/************************************************************************/
4256
/*               GDALAlgorithmArgGetMutualExclusionGroup()              */
4257
/************************************************************************/
4258

4259
/** Return the name of the mutual exclusion group to which this argument
4260
 * belongs to.
4261
 *
4262
 * Or empty string if it does not belong to any exclusion group.
4263
 *
4264
 * @param hArg Handle to an argument. Must NOT be null.
4265
 * @return string whose lifetime is bound to hArg and which must not
4266
 * be freed.
4267
 * @since 3.11
4268
 */
4269
const char *GDALAlgorithmArgGetMutualExclusionGroup(GDALAlgorithmArgH hArg)
1✔
4270
{
4271
    VALIDATE_POINTER1(hArg, __func__, nullptr);
1✔
4272
    return hArg->ptr->GetMutualExclusionGroup().c_str();
1✔
4273
}
4274

4275
/************************************************************************/
4276
/*                    GDALAlgorithmArgGetAsBoolean()                    */
4277
/************************************************************************/
4278

4279
/** Return the argument value as a boolean.
4280
 *
4281
 * Must only be called on arguments whose type is GAAT_BOOLEAN.
4282
 *
4283
 * @param hArg Handle to an argument. Must NOT be null.
4284
 * @since 3.11
4285
 */
4286
bool GDALAlgorithmArgGetAsBoolean(GDALAlgorithmArgH hArg)
4✔
4287
{
4288
    VALIDATE_POINTER1(hArg, __func__, false);
4✔
4289
    if (hArg->ptr->GetType() != GAAT_BOOLEAN)
4✔
4290
    {
4291
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
4292
                 "%s must only be called on arguments of type GAAT_BOOLEAN",
4293
                 __func__);
4294
        return false;
1✔
4295
    }
4296
    return hArg->ptr->Get<bool>();
3✔
4297
}
4298

4299
/************************************************************************/
4300
/*                    GDALAlgorithmArgGetAsBoolean()                    */
4301
/************************************************************************/
4302

4303
/** Return the argument value as a string.
4304
 *
4305
 * Must only be called on arguments whose type is GAAT_STRING.
4306
 *
4307
 * @param hArg Handle to an argument. Must NOT be null.
4308
 * @return string whose lifetime is bound to hArg and which must not
4309
 * be freed.
4310
 * @since 3.11
4311
 */
4312
const char *GDALAlgorithmArgGetAsString(GDALAlgorithmArgH hArg)
26✔
4313
{
4314
    VALIDATE_POINTER1(hArg, __func__, nullptr);
26✔
4315
    if (hArg->ptr->GetType() != GAAT_STRING)
26✔
4316
    {
4317
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
4318
                 "%s must only be called on arguments of type GAAT_STRING",
4319
                 __func__);
4320
        return nullptr;
1✔
4321
    }
4322
    return hArg->ptr->Get<std::string>().c_str();
25✔
4323
}
4324

4325
/************************************************************************/
4326
/*                 GDALAlgorithmArgGetAsDatasetValue()                  */
4327
/************************************************************************/
4328

4329
/** Return the argument value as a GDALArgDatasetValueH.
4330
 *
4331
 * Must only be called on arguments whose type is GAAT_DATASET
4332
 *
4333
 * @param hArg Handle to an argument. Must NOT be null.
4334
 * @return handle to a GDALArgDatasetValue that must be released with
4335
 * GDALArgDatasetValueRelease(). The lifetime of that handle does not exceed
4336
 * the one of hArg.
4337
 * @since 3.11
4338
 */
4339
GDALArgDatasetValueH GDALAlgorithmArgGetAsDatasetValue(GDALAlgorithmArgH hArg)
164✔
4340
{
4341
    VALIDATE_POINTER1(hArg, __func__, nullptr);
164✔
4342
    if (hArg->ptr->GetType() != GAAT_DATASET)
164✔
4343
    {
4344
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
4345
                 "%s must only be called on arguments of type GAAT_DATASET",
4346
                 __func__);
4347
        return nullptr;
1✔
4348
    }
4349
    return std::make_unique<GDALArgDatasetValueHS>(
163✔
4350
               &(hArg->ptr->Get<GDALArgDatasetValue>()))
326✔
4351
        .release();
163✔
4352
}
4353

4354
/************************************************************************/
4355
/*                    GDALAlgorithmArgGetAsInteger()                    */
4356
/************************************************************************/
4357

4358
/** Return the argument value as a integer.
4359
 *
4360
 * Must only be called on arguments whose type is GAAT_INTEGER
4361
 *
4362
 * @param hArg Handle to an argument. Must NOT be null.
4363
 * @since 3.11
4364
 */
4365
int GDALAlgorithmArgGetAsInteger(GDALAlgorithmArgH hArg)
2✔
4366
{
4367
    VALIDATE_POINTER1(hArg, __func__, 0);
2✔
4368
    if (hArg->ptr->GetType() != GAAT_INTEGER)
2✔
4369
    {
4370
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
4371
                 "%s must only be called on arguments of type GAAT_INTEGER",
4372
                 __func__);
4373
        return 0;
1✔
4374
    }
4375
    return hArg->ptr->Get<int>();
1✔
4376
}
4377

4378
/************************************************************************/
4379
/*                    GDALAlgorithmArgGetAsDouble()                     */
4380
/************************************************************************/
4381

4382
/** Return the argument value as a double.
4383
 *
4384
 * Must only be called on arguments whose type is GAAT_REAL
4385
 *
4386
 * @param hArg Handle to an argument. Must NOT be null.
4387
 * @since 3.11
4388
 */
4389
double GDALAlgorithmArgGetAsDouble(GDALAlgorithmArgH hArg)
2✔
4390
{
4391
    VALIDATE_POINTER1(hArg, __func__, 0);
2✔
4392
    if (hArg->ptr->GetType() != GAAT_REAL)
2✔
4393
    {
4394
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
4395
                 "%s must only be called on arguments of type GAAT_REAL",
4396
                 __func__);
4397
        return 0;
1✔
4398
    }
4399
    return hArg->ptr->Get<double>();
1✔
4400
}
4401

4402
/************************************************************************/
4403
/*                   GDALAlgorithmArgGetAsStringList()                  */
4404
/************************************************************************/
4405

4406
/** Return the argument value as a double.
4407
 *
4408
 * Must only be called on arguments whose type is GAAT_STRING_LIST.
4409
 *
4410
 * @param hArg Handle to an argument. Must NOT be null.
4411
 * @return a NULL terminated list of names, which must be destroyed with
4412
 * CSLDestroy()
4413

4414
 * @since 3.11
4415
 */
4416
char **GDALAlgorithmArgGetAsStringList(GDALAlgorithmArgH hArg)
2✔
4417
{
4418
    VALIDATE_POINTER1(hArg, __func__, nullptr);
2✔
4419
    if (hArg->ptr->GetType() != GAAT_STRING_LIST)
2✔
4420
    {
4421
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
4422
                 "%s must only be called on arguments of type GAAT_STRING_LIST",
4423
                 __func__);
4424
        return nullptr;
1✔
4425
    }
4426
    return CPLStringList(hArg->ptr->Get<std::vector<std::string>>())
2✔
4427
        .StealList();
1✔
4428
}
4429

4430
/************************************************************************/
4431
/*                  GDALAlgorithmArgGetAsIntegerList()                  */
4432
/************************************************************************/
4433

4434
/** Return the argument value as a integer.
4435
 *
4436
 * Must only be called on arguments whose type is GAAT_INTEGER
4437
 *
4438
 * @param hArg Handle to an argument. Must NOT be null.
4439
 * @param[out] pnCount Pointer to the number of values in the list. Must NOT be null.
4440
 * @since 3.11
4441
 */
4442
const int *GDALAlgorithmArgGetAsIntegerList(GDALAlgorithmArgH hArg,
2✔
4443
                                            size_t *pnCount)
4444
{
4445
    VALIDATE_POINTER1(hArg, __func__, nullptr);
2✔
4446
    VALIDATE_POINTER1(pnCount, __func__, nullptr);
2✔
4447
    if (hArg->ptr->GetType() != GAAT_INTEGER_LIST)
2✔
4448
    {
4449
        CPLError(
1✔
4450
            CE_Failure, CPLE_AppDefined,
4451
            "%s must only be called on arguments of type GAAT_INTEGER_LIST",
4452
            __func__);
4453
        *pnCount = 0;
1✔
4454
        return nullptr;
1✔
4455
    }
4456
    const auto &val = hArg->ptr->Get<std::vector<int>>();
1✔
4457
    *pnCount = val.size();
1✔
4458
    return val.data();
1✔
4459
}
4460

4461
/************************************************************************/
4462
/*                  GDALAlgorithmArgGetAsDoubleList()                   */
4463
/************************************************************************/
4464

4465
/** Return the argument value as a integer.
4466
 *
4467
 * Must only be called on arguments whose type is GAAT_INTEGER
4468
 *
4469
 * @param hArg Handle to an argument. Must NOT be null.
4470
 * @param[out] pnCount Pointer to the number of values in the list. Must NOT be null.
4471
 * @since 3.11
4472
 */
4473
const double *GDALAlgorithmArgGetAsDoubleList(GDALAlgorithmArgH hArg,
2✔
4474
                                              size_t *pnCount)
4475
{
4476
    VALIDATE_POINTER1(hArg, __func__, nullptr);
2✔
4477
    VALIDATE_POINTER1(pnCount, __func__, nullptr);
2✔
4478
    if (hArg->ptr->GetType() != GAAT_REAL_LIST)
2✔
4479
    {
4480
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
4481
                 "%s must only be called on arguments of type GAAT_REAL_LIST",
4482
                 __func__);
4483
        *pnCount = 0;
1✔
4484
        return nullptr;
1✔
4485
    }
4486
    const auto &val = hArg->ptr->Get<std::vector<double>>();
1✔
4487
    *pnCount = val.size();
1✔
4488
    return val.data();
1✔
4489
}
4490

4491
/************************************************************************/
4492
/*                    GDALAlgorithmArgSetAsBoolean()                    */
4493
/************************************************************************/
4494

4495
/** Set the value for a GAAT_BOOLEAN argument.
4496
 *
4497
 * It cannot be called several times for a given argument.
4498
 * Validation checks and other actions are run.
4499
 *
4500
 * @param hArg Handle to an argument. Must NOT be null.
4501
 * @param value value.
4502
 * @return true if success.
4503
 * @since 3.11
4504
 */
4505

4506
bool GDALAlgorithmArgSetAsBoolean(GDALAlgorithmArgH hArg, bool value)
8✔
4507
{
4508
    VALIDATE_POINTER1(hArg, __func__, false);
8✔
4509
    return hArg->ptr->Set(value);
8✔
4510
}
4511

4512
/************************************************************************/
4513
/*                    GDALAlgorithmArgSetAsString()                     */
4514
/************************************************************************/
4515

4516
/** Set the value for a GAAT_STRING argument.
4517
 *
4518
 * It cannot be called several times for a given argument.
4519
 * Validation checks and other actions are run.
4520
 *
4521
 * @param hArg Handle to an argument. Must NOT be null.
4522
 * @param value value (may be null)
4523
 * @return true if success.
4524
 * @since 3.11
4525
 */
4526

4527
bool GDALAlgorithmArgSetAsString(GDALAlgorithmArgH hArg, const char *value)
25✔
4528
{
4529
    VALIDATE_POINTER1(hArg, __func__, false);
25✔
4530
    return hArg->ptr->Set(value ? value : "");
25✔
4531
}
4532

4533
/************************************************************************/
4534
/*                    GDALAlgorithmArgSetAsInteger()                    */
4535
/************************************************************************/
4536

4537
/** Set the value for a GAAT_INTEGER (or GAAT_REAL) argument.
4538
 *
4539
 * It cannot be called several times for a given argument.
4540
 * Validation checks and other actions are run.
4541
 *
4542
 * @param hArg Handle to an argument. Must NOT be null.
4543
 * @param value value.
4544
 * @return true if success.
4545
 * @since 3.11
4546
 */
4547

4548
bool GDALAlgorithmArgSetAsInteger(GDALAlgorithmArgH hArg, int value)
5✔
4549
{
4550
    VALIDATE_POINTER1(hArg, __func__, false);
5✔
4551
    return hArg->ptr->Set(value);
5✔
4552
}
4553

4554
/************************************************************************/
4555
/*                    GDALAlgorithmArgSetAsDouble()                     */
4556
/************************************************************************/
4557

4558
/** Set the value for a GAAT_REAL argument.
4559
 *
4560
 * It cannot be called several times for a given argument.
4561
 * Validation checks and other actions are run.
4562
 *
4563
 * @param hArg Handle to an argument. Must NOT be null.
4564
 * @param value value.
4565
 * @return true if success.
4566
 * @since 3.11
4567
 */
4568

4569
bool GDALAlgorithmArgSetAsDouble(GDALAlgorithmArgH hArg, double value)
1✔
4570
{
4571
    VALIDATE_POINTER1(hArg, __func__, false);
1✔
4572
    return hArg->ptr->Set(value);
1✔
4573
}
4574

4575
/************************************************************************/
4576
/*                 GDALAlgorithmArgSetAsDatasetValue()                  */
4577
/************************************************************************/
4578

4579
/** Set the value for a GAAT_DATASET argument.
4580
 *
4581
 * It cannot be called several times for a given argument.
4582
 * Validation checks and other actions are run.
4583
 *
4584
 * @param hArg Handle to an argument. Must NOT be null.
4585
 * @param value Handle to a GDALArgDatasetValue. Must NOT be null.
4586
 * @return true if success.
4587
 * @since 3.11
4588
 */
4589
bool GDALAlgorithmArgSetAsDatasetValue(GDALAlgorithmArgH hArg,
2✔
4590
                                       GDALArgDatasetValueH value)
4591
{
4592
    VALIDATE_POINTER1(hArg, __func__, false);
2✔
4593
    VALIDATE_POINTER1(value, __func__, false);
2✔
4594
    return hArg->ptr->SetFrom(*(value->ptr));
2✔
4595
}
4596

4597
/************************************************************************/
4598
/*                     GDALAlgorithmArgSetDataset()                     */
4599
/************************************************************************/
4600

4601
/** Set dataset object, increasing its reference counter.
4602
 *
4603
 * @param hArg Handle to an argument. Must NOT be null.
4604
 * @param hDS Dataset object. May be null.
4605
 * @return true if success.
4606
 * @since 3.11
4607
 */
4608

4609
bool GDALAlgorithmArgSetDataset(GDALAlgorithmArgH hArg, GDALDatasetH hDS)
3✔
4610
{
4611
    VALIDATE_POINTER1(hArg, __func__, false);
3✔
4612
    return hArg->ptr->Set(GDALDataset::FromHandle(hDS));
3✔
4613
}
4614

4615
/************************************************************************/
4616
/*                  GDALAlgorithmArgSetAsStringList()                   */
4617
/************************************************************************/
4618

4619
/** Set the value for a GAAT_STRING_LIST argument.
4620
 *
4621
 * It cannot be called several times for a given argument.
4622
 * Validation checks and other actions are run.
4623
 *
4624
 * @param hArg Handle to an argument. Must NOT be null.
4625
 * @param value value as a NULL terminated list (may be null)
4626
 * @return true if success.
4627
 * @since 3.11
4628
 */
4629

4630
bool GDALAlgorithmArgSetAsStringList(GDALAlgorithmArgH hArg, CSLConstList value)
70✔
4631
{
4632
    VALIDATE_POINTER1(hArg, __func__, false);
70✔
4633
    return hArg->ptr->Set(
70✔
4634
        static_cast<std::vector<std::string>>(CPLStringList(value)));
140✔
4635
}
4636

4637
/************************************************************************/
4638
/*                  GDALAlgorithmArgSetAsIntegerList()                  */
4639
/************************************************************************/
4640

4641
/** Set the value for a GAAT_INTEGER_LIST argument.
4642
 *
4643
 * It cannot be called several times for a given argument.
4644
 * Validation checks and other actions are run.
4645
 *
4646
 * @param hArg Handle to an argument. Must NOT be null.
4647
 * @param nCount Number of values in pnValues.
4648
 * @param pnValues Pointer to an array of integer values of size nCount.
4649
 * @return true if success.
4650
 * @since 3.11
4651
 */
4652
bool GDALAlgorithmArgSetAsIntegerList(GDALAlgorithmArgH hArg, size_t nCount,
4✔
4653
                                      const int *pnValues)
4654
{
4655
    VALIDATE_POINTER1(hArg, __func__, false);
4✔
4656
    return hArg->ptr->Set(std::vector<int>(pnValues, pnValues + nCount));
4✔
4657
}
4658

4659
/************************************************************************/
4660
/*                   GDALAlgorithmArgSetAsDoubleList()                  */
4661
/************************************************************************/
4662

4663
/** Set the value for a GAAT_REAL_LIST argument.
4664
 *
4665
 * It cannot be called several times for a given argument.
4666
 * Validation checks and other actions are run.
4667
 *
4668
 * @param hArg Handle to an argument. Must NOT be null.
4669
 * @param nCount Number of values in pnValues.
4670
 * @param pnValues Pointer to an array of double values of size nCount.
4671
 * @return true if success.
4672
 * @since 3.11
4673
 */
4674
bool GDALAlgorithmArgSetAsDoubleList(GDALAlgorithmArgH hArg, size_t nCount,
6✔
4675
                                     const double *pnValues)
4676
{
4677
    VALIDATE_POINTER1(hArg, __func__, false);
6✔
4678
    return hArg->ptr->Set(std::vector<double>(pnValues, pnValues + nCount));
6✔
4679
}
4680

4681
/************************************************************************/
4682
/*                     GDALAlgorithmArgSetDatasets()                    */
4683
/************************************************************************/
4684

4685
/** Set dataset objects to a GAAT_DATASET_LIST argument, increasing their reference counter.
4686
 *
4687
 * @param hArg Handle to an argument. Must NOT be null.
4688
 * @param nCount Number of values in pnValues.
4689
 * @param pahDS Pointer to an array of dataset of size nCount.
4690
 * @return true if success.
4691
 * @since 3.11
4692
 */
4693

4694
bool GDALAlgorithmArgSetDatasets(GDALAlgorithmArgH hArg, size_t nCount,
10✔
4695
                                 GDALDatasetH *pahDS)
4696
{
4697
    VALIDATE_POINTER1(hArg, __func__, false);
10✔
4698
    std::vector<GDALArgDatasetValue> values;
20✔
4699
    for (size_t i = 0; i < nCount; ++i)
28✔
4700
    {
4701
        values.emplace_back(GDALDataset::FromHandle(pahDS[i]));
18✔
4702
    }
4703
    return hArg->ptr->Set(std::move(values));
10✔
4704
}
4705

4706
/************************************************************************/
4707
/*                    GDALAlgorithmArgSetDatasetNames()                 */
4708
/************************************************************************/
4709

4710
/** Set dataset names to a GAAT_DATASET_LIST argument.
4711
 *
4712
 * @param hArg Handle to an argument. Must NOT be null.
4713
 * @param names Dataset names as a NULL terminated list (may be null)
4714
 * @return true if success.
4715
 * @since 3.11
4716
 */
4717

4718
bool GDALAlgorithmArgSetDatasetNames(GDALAlgorithmArgH hArg, CSLConstList names)
7✔
4719
{
4720
    VALIDATE_POINTER1(hArg, __func__, false);
7✔
4721
    std::vector<GDALArgDatasetValue> values;
14✔
4722
    for (size_t i = 0; names[i]; ++i)
14✔
4723
    {
4724
        values.emplace_back(names[i]);
7✔
4725
    }
4726
    return hArg->ptr->Set(std::move(values));
7✔
4727
}
4728

4729
/************************************************************************/
4730
/*                      GDALArgDatasetValueCreate()                     */
4731
/************************************************************************/
4732

4733
/** Instantiate an empty GDALArgDatasetValue
4734
 *
4735
 * @return new handle to free with GDALArgDatasetValueRelease()
4736
 * @since 3.11
4737
 */
4738
GDALArgDatasetValueH GDALArgDatasetValueCreate()
1✔
4739
{
4740
    return std::make_unique<GDALArgDatasetValueHS>().release();
1✔
4741
}
4742

4743
/************************************************************************/
4744
/*                      GDALArgDatasetValueRelease()                    */
4745
/************************************************************************/
4746

4747
/** Release a handle to a GDALArgDatasetValue
4748
 *
4749
 * @since 3.11
4750
 */
4751
void GDALArgDatasetValueRelease(GDALArgDatasetValueH hValue)
164✔
4752
{
4753
    delete hValue;
164✔
4754
}
164✔
4755

4756
/************************************************************************/
4757
/*                    GDALArgDatasetValueGetName()                      */
4758
/************************************************************************/
4759

4760
/** Return the name component of the GDALArgDatasetValue
4761
 *
4762
 * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4763
 * @return string whose lifetime is bound to hAlg and which must not
4764
 * be freed.
4765
 * @since 3.11
4766
 */
4767
const char *GDALArgDatasetValueGetName(GDALArgDatasetValueH hValue)
1✔
4768
{
4769
    VALIDATE_POINTER1(hValue, __func__, nullptr);
1✔
4770
    return hValue->ptr->GetName().c_str();
1✔
4771
}
4772

4773
/************************************************************************/
4774
/*               GDALArgDatasetValueGetDatasetRef()                     */
4775
/************************************************************************/
4776

4777
/** Return the dataset component of the GDALArgDatasetValue.
4778
 *
4779
 * This does not modify the reference counter, hence the lifetime of the
4780
 * returned object is not guaranteed to exceed the one of hValue.
4781
 *
4782
 * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4783
 * @since 3.11
4784
 */
4785
GDALDatasetH GDALArgDatasetValueGetDatasetRef(GDALArgDatasetValueH hValue)
3✔
4786
{
4787
    VALIDATE_POINTER1(hValue, __func__, nullptr);
3✔
4788
    return GDALDataset::ToHandle(hValue->ptr->GetDatasetRef());
3✔
4789
}
4790

4791
/************************************************************************/
4792
/*               GDALArgDatasetValueGetDatasetIncreaseRefCount()        */
4793
/************************************************************************/
4794

4795
/** Return the dataset component of the GDALArgDatasetValue, and increase its
4796
 * reference count if not null. Once done with the dataset, the caller should
4797
 * call GDALReleaseDataset().
4798
 *
4799
 * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4800
 * @since 3.11
4801
 */
4802
GDALDatasetH
4803
GDALArgDatasetValueGetDatasetIncreaseRefCount(GDALArgDatasetValueH hValue)
45✔
4804
{
4805
    VALIDATE_POINTER1(hValue, __func__, nullptr);
45✔
4806
    return GDALDataset::ToHandle(hValue->ptr->GetDatasetIncreaseRefCount());
45✔
4807
}
4808

4809
/************************************************************************/
4810
/*                    GDALArgDatasetValueGetType()                      */
4811
/************************************************************************/
4812

4813
/** Get which type of dataset is allowed / generated.
4814
 *
4815
 * Binary-or combination of GDAL_OF_RASTER, GDAL_OF_VECTOR and
4816
 * GDAL_OF_MULTIDIM_RASTER.
4817
 *
4818
 * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4819
 * @since 3.11
4820
 */
4821
GDALArgDatasetValueType GDALArgDatasetValueGetType(GDALArgDatasetValueH hValue)
1✔
4822
{
4823
    VALIDATE_POINTER1(hValue, __func__, 0);
1✔
4824
    return hValue->ptr->GetType();
1✔
4825
}
4826

4827
/************************************************************************/
4828
/*                   GDALArgDatasetValueGetInputFlags()                 */
4829
/************************************************************************/
4830

4831
/** Indicates which components among name and dataset are accepted as
4832
 * input, when this argument serves as an input.
4833
 *
4834
 * If the GADV_NAME bit is set, it indicates a dataset name is accepted as
4835
 * input.
4836
 * If the GADV_OBJECT bit is set, it indicates a dataset object is
4837
 * accepted as input.
4838
 * If both bits are set, the algorithm can accept either a name or a dataset
4839
 * object.
4840
 *
4841
 * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4842
 * @return string whose lifetime is bound to hAlg and which must not
4843
 * be freed.
4844
 * @since 3.11
4845
 */
4846
int GDALArgDatasetValueGetInputFlags(GDALArgDatasetValueH hValue)
1✔
4847
{
4848
    VALIDATE_POINTER1(hValue, __func__, 0);
1✔
4849
    return hValue->ptr->GetInputFlags();
1✔
4850
}
4851

4852
/************************************************************************/
4853
/*                  GDALArgDatasetValueGetOutputFlags()                 */
4854
/************************************************************************/
4855

4856
/** Indicates which components among name and dataset are modified,
4857
 * when this argument serves as an output.
4858
 *
4859
 * If the GADV_NAME bit is set, it indicates a dataset name is generated as
4860
 * output (that is the algorithm will generate the name. Rarely used).
4861
 * If the GADV_OBJECT bit is set, it indicates a dataset object is
4862
 * generated as output, and available for use after the algorithm has
4863
 * completed.
4864
 *
4865
 * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4866
 * @return string whose lifetime is bound to hAlg and which must not
4867
 * be freed.
4868
 * @since 3.11
4869
 */
4870
int GDALArgDatasetValueGetOutputFlags(GDALArgDatasetValueH hValue)
1✔
4871
{
4872
    VALIDATE_POINTER1(hValue, __func__, 0);
1✔
4873
    return hValue->ptr->GetOutputFlags();
1✔
4874
}
4875

4876
/************************************************************************/
4877
/*                    GDALArgDatasetValueSetName()                      */
4878
/************************************************************************/
4879

4880
/** Set dataset name
4881
 *
4882
 * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4883
 * @param pszName Dataset name. May be null.
4884
 * @since 3.11
4885
 */
4886

4887
void GDALArgDatasetValueSetName(GDALArgDatasetValueH hValue,
58✔
4888
                                const char *pszName)
4889
{
4890
    VALIDATE_POINTER0(hValue, __func__);
58✔
4891
    hValue->ptr->Set(pszName ? pszName : "");
58✔
4892
}
4893

4894
/************************************************************************/
4895
/*                  GDALArgDatasetValueSetDataset()                     */
4896
/************************************************************************/
4897

4898
/** Set dataset object, increasing its reference counter.
4899
 *
4900
 * @param hValue Handle to a GDALArgDatasetValue. Must NOT be null.
4901
 * @param hDS Dataset object. May be null.
4902
 * @since 3.11
4903
 */
4904

4905
void GDALArgDatasetValueSetDataset(GDALArgDatasetValueH hValue,
63✔
4906
                                   GDALDatasetH hDS)
4907
{
4908
    VALIDATE_POINTER0(hValue, __func__);
63✔
4909
    hValue->ptr->Set(GDALDataset::FromHandle(hDS));
63✔
4910
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc