Coverage Report

Created: 2026-07-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_main.cpp
Line
Count
Source
1
/******************************************************************************
2
*
3
* Project:  GDAL
4
* Purpose:  gdal "main" command
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 "gdalalg_main.h"
14
15
#include "gdal_priv.h"
16
17
#if !defined(_WIN32)
18
#include <unistd.h>
19
#endif
20
21
//! @cond Doxygen_Suppress
22
23
#ifndef _
24
0
#define _(x) (x)
25
#endif
26
27
/************************************************************************/
28
/*                GDALMainAlgorithm::GDALMainAlgorithm()                */
29
/************************************************************************/
30
31
GDALMainAlgorithm::GDALMainAlgorithm()
32
0
    : GDALAlgorithm(NAME, DESCRIPTION, HELP_URL)
33
0
{
34
0
    for (const std::string &subAlgName :
35
0
         GDALGlobalAlgorithmRegistry::GetSingleton().GetNames())
36
0
    {
37
0
        const auto pInfo =
38
0
            GDALGlobalAlgorithmRegistry::GetSingleton().GetInfo(subAlgName);
39
0
        if (pInfo)
40
0
            RegisterSubAlgorithm(*pInfo);
41
0
    }
42
43
0
    SetCallPath({NAME});
44
45
0
    AddArg("version", 0, _("Display GDAL version and exit"), &m_version)
46
0
        .SetHiddenForAPI();
47
0
    AddArg("drivers", 0, _("Display driver list as JSON document"), &m_drivers);
48
49
0
    AddOutputStringArg(&m_output);
50
51
0
    m_longDescription = "'gdal <FILENAME>' can also be used as a shortcut for "
52
0
                        "'gdal info <FILENAME>'.\n"
53
0
                        "And 'gdal read <FILENAME> ! ...' as a shortcut for "
54
0
                        "'gdal pipeline <FILENAME> ! ...'.";
55
56
0
    SetDisplayInJSONUsage(false);
57
0
}
58
59
/************************************************************************/
60
/*            GDALMainAlgorithm::ParseCommandLineArguments()            */
61
/************************************************************************/
62
63
bool GDALMainAlgorithm::ParseCommandLineArguments(
64
    const std::vector<std::string> &args)
65
0
{
66
    // Detect shortest form of pipeline:
67
    // "gdal read in.tif ! .... ! write out.tif"
68
0
    if (args.size() >= 2 && args[0] == "read")
69
0
    {
70
0
        m_subAlg =
71
0
            GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate("pipeline");
72
0
        if (m_subAlg)
73
0
        {
74
0
            if (IsCalledFromCommandLine())
75
0
                m_subAlg->SetCalledFromCommandLine();
76
0
            bool ret = m_subAlg->ParseCommandLineArguments(args);
77
0
            if (ret)
78
0
            {
79
0
                m_selectedSubAlg = &(m_subAlg->GetActualAlgorithm());
80
0
                std::vector<std::string> callPath(m_callPath);
81
0
                callPath.push_back("vector");
82
0
                m_selectedSubAlg->SetCallPath(callPath);
83
0
                return true;
84
0
            }
85
0
            else if (strstr(CPLGetLastErrorMsg(),
86
0
                            "has both raster and vector content"))
87
0
            {
88
0
                m_showUsage = false;
89
0
                return false;
90
0
            }
91
0
        }
92
93
0
        return false;
94
0
    }
95
0
    else if (args.size() == 1 && args[0].size() >= 2 && args[0][0] == '-' &&
96
0
             args[0][1] == '-')
97
0
    {
98
0
        return GDALAlgorithm::ParseCommandLineArguments(args);
99
0
    }
100
101
    // Generic case: "gdal {subcommand} arguments"
102
    // where subcommand is a known subcommand
103
0
    else if (args.size() >= 1)
104
0
    {
105
0
        const auto nCounter = CPLGetErrorCounter();
106
0
        if (InstantiateSubAlgorithm(args[0]))
107
0
            return GDALAlgorithm::ParseCommandLineArguments(args);
108
0
        if (CPLGetErrorCounter() == nCounter + 1 &&
109
0
            strstr(CPLGetLastErrorMsg(), "Do you mean"))
110
0
        {
111
0
            return false;
112
0
        }
113
0
    }
114
115
    // Otherwise check if that is the shortest form of "gdal read mydataset"
116
    // where "read" is omitted: "gdal in.tif"
117
0
    {
118
0
        VSIStatBufL sStat;
119
0
        std::vector<char> osResolvedFilename(2048);
120
0
        for (const auto &arg : args)
121
0
        {
122
0
            if (VSIStatL(arg.c_str(), &sStat) == 0
123
0
#if !defined(_WIN32)
124
0
                || readlink(arg.c_str(), osResolvedFilename.data(),
125
0
                            osResolvedFilename.size()) != -1
126
0
#endif
127
0
            )
128
0
            {
129
0
                m_subAlg =
130
0
                    GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate(
131
0
                        "info");
132
0
                if (m_subAlg)
133
0
                {
134
0
                    bool ret = m_subAlg->ParseCommandLineArguments(args);
135
0
                    if (ret)
136
0
                    {
137
0
                        m_selectedSubAlg = &(m_subAlg->GetActualAlgorithm());
138
0
                        std::vector<std::string> callPath(m_callPath);
139
0
                        callPath.push_back(m_selectedSubAlg->GetArg("layer")
140
0
                                               ? "vector"
141
0
                                               : "raster");
142
0
                        m_selectedSubAlg->SetCallPath(callPath);
143
0
                        return true;
144
0
                    }
145
0
                    else if (strstr(CPLGetLastErrorMsg(),
146
0
                                    "has both raster and vector content"))
147
0
                    {
148
0
                        m_showUsage = false;
149
0
                        return false;
150
0
                    }
151
0
                }
152
0
            }
153
0
        }
154
155
0
        return GDALAlgorithm::ParseCommandLineArguments(args);
156
0
    }
157
0
}
158
159
/************************************************************************/
160
/*                 GDALMainAlgorithm::GetUsageForCLI()                  */
161
/************************************************************************/
162
163
std::string
164
GDALMainAlgorithm::GetUsageForCLI(bool shortUsage,
165
                                  const UsageOptions &usageOptions) const
166
0
{
167
0
    if (m_selectedSubAlg)
168
0
        return m_selectedSubAlg->GetUsageForCLI(shortUsage, usageOptions);
169
0
    if (m_showUsage)
170
0
        return GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptions);
171
0
    return std::string();
172
0
}
173
174
/************************************************************************/
175
/*                     GDALMainAlgorithm::RunImpl()                     */
176
/************************************************************************/
177
178
bool GDALMainAlgorithm::RunImpl(GDALProgressFunc, void *)
179
0
{
180
0
    if (m_drivers)
181
0
    {
182
0
        m_output = GDALPrintDriverList(GDAL_OF_KIND_MASK, true);
183
0
    }
184
0
    return true;
185
0
}
186
187
//! @endcond