Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Utilities
4 : * Purpose: Command line utility for GDAL identify, delete, rename and copy
5 : * (by file) operations.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : * ****************************************************************************
9 : * Copyright (c) 2007, Frank Warmerdam
10 : * Copyright (c) 2008-2009, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "cpl_string.h"
16 : #include "cpl_conv.h"
17 : #include "gdal_version.h"
18 : #include "gdal.h"
19 : #include "commonutils.h"
20 : #include "gdalargumentparser.h"
21 :
22 : /************************************************************************/
23 : /* GDALManageOptions() */
24 : /************************************************************************/
25 :
26 : struct GDALManageOptions
27 : {
28 : bool bRecursive = false;
29 : bool bForceRecurse = false;
30 : bool bReportFailures = false;
31 : std::string osNewName;
32 : std::string osDatasetName;
33 : std::vector<std::string> aosDatasetNames;
34 : std::string osDriverName;
35 : };
36 :
37 : /************************************************************************/
38 : /* ProcessIdentifyTarget() */
39 : /************************************************************************/
40 :
41 191 : static void ProcessIdentifyTarget(const char *pszTarget,
42 : char **papszSiblingList, bool bRecursive,
43 : bool bReportFailures, bool bForceRecurse)
44 :
45 : {
46 : GDALDriverH hDriver;
47 : VSIStatBufL sStatBuf;
48 : int i;
49 :
50 191 : hDriver = GDALIdentifyDriver(pszTarget, papszSiblingList);
51 :
52 191 : if (hDriver != nullptr)
53 143 : printf("%s: %s\n", pszTarget, GDALGetDriverShortName(hDriver));
54 48 : else if (bReportFailures)
55 16 : printf("%s: unrecognized\n", pszTarget);
56 :
57 191 : if (!bForceRecurse && (!bRecursive || hDriver != nullptr))
58 188 : return;
59 :
60 186 : if (VSIStatL(pszTarget, &sStatBuf) != 0 || !VSI_ISDIR(sStatBuf.st_mode))
61 183 : return;
62 :
63 3 : papszSiblingList = VSIReadDir(pszTarget);
64 192 : for (i = 0; papszSiblingList && papszSiblingList[i]; i++)
65 : {
66 189 : if (EQUAL(papszSiblingList[i], "..") || EQUAL(papszSiblingList[i], "."))
67 6 : continue;
68 :
69 : const CPLString osSubTarget =
70 366 : CPLFormFilenameSafe(pszTarget, papszSiblingList[i], nullptr);
71 :
72 183 : ProcessIdentifyTarget(osSubTarget, papszSiblingList, bRecursive,
73 : bReportFailures, bForceRecurse);
74 : }
75 3 : CSLDestroy(papszSiblingList);
76 : }
77 :
78 : /************************************************************************/
79 : /* GDALManageAppOptionsGetParser() */
80 : /************************************************************************/
81 :
82 : static std::unique_ptr<GDALArgumentParser>
83 21 : GDALManageAppOptionsGetParser(GDALManageOptions *psOptions)
84 : {
85 : auto argParser = std::make_unique<GDALArgumentParser>(
86 21 : "gdalmanage", /* bForBinary */ true);
87 :
88 21 : argParser->add_description(
89 21 : _("Identify, delete, rename and copy raster data files."));
90 21 : argParser->add_epilog(_("For more details, consult the full documentation "
91 : "for the gdalmanage utility "
92 21 : "https://gdal.org/programs/gdalmanage.html"));
93 :
94 : auto addCommonOptions =
95 168 : [psOptions](GDALArgumentParser *subParser, const char *helpMessageSrc)
96 : {
97 42 : subParser->add_argument("-f")
98 84 : .metavar("<format>")
99 42 : .store_into(psOptions->osDriverName)
100 : .help(_("Specify format of raster file if unknown by the "
101 42 : "application."));
102 :
103 42 : subParser->add_argument("datasetname")
104 84 : .metavar("<datasetname>")
105 42 : .store_into(psOptions->osDatasetName)
106 42 : .help(helpMessageSrc);
107 :
108 42 : subParser->add_argument("newdatasetname")
109 84 : .metavar("<newdatasetname>")
110 42 : .store_into(psOptions->osNewName)
111 42 : .help(_("Name of the new file."));
112 42 : };
113 :
114 : // Identify
115 :
116 : auto identifyParser =
117 21 : argParser->add_subparser("identify", /* bForBinary */ true);
118 21 : identifyParser->add_description(_("List data format of file(s)."));
119 :
120 21 : identifyParser->add_argument("-r")
121 21 : .flag()
122 21 : .store_into(psOptions->bRecursive)
123 21 : .help(_("Recursively scan files/folders for raster files."));
124 :
125 21 : identifyParser->add_argument("-fr")
126 21 : .flag()
127 21 : .store_into(psOptions->bRecursive)
128 21 : .store_into(psOptions->bForceRecurse)
129 : .help(_("Recursively scan folders for raster files, forcing "
130 21 : "recursion in folders recognized as valid formats."));
131 :
132 21 : identifyParser->add_argument("-u")
133 21 : .flag()
134 21 : .store_into(psOptions->bReportFailures)
135 21 : .help(_("Report failures if file type is unidentified."));
136 :
137 : // Note: this accepts multiple files
138 21 : identifyParser->add_argument("datasetname")
139 42 : .metavar("<datasetname>")
140 21 : .store_into(psOptions->aosDatasetNames)
141 21 : .remaining()
142 21 : .help(_("Name(s) of the file(s) to identify."));
143 :
144 : // Copy
145 :
146 21 : auto copyParser = argParser->add_subparser("copy", /* bForBinary */ true);
147 : copyParser->add_description(
148 21 : _("Create a copy of the raster file with a new name."));
149 :
150 21 : addCommonOptions(copyParser, _("Name of the file to copy."));
151 :
152 : // Rename
153 :
154 : auto renameParser =
155 21 : argParser->add_subparser("rename", /* bForBinary */ true);
156 21 : renameParser->add_description(_("Change the name of the raster file."));
157 :
158 21 : addCommonOptions(renameParser, _("Name of the file to rename."));
159 :
160 : // Delete
161 :
162 : auto deleteParser =
163 21 : argParser->add_subparser("delete", /* bForBinary */ true);
164 21 : deleteParser->add_description(_("Delete the raster file(s)."));
165 :
166 : // Note: this accepts multiple files
167 21 : deleteParser->add_argument("datasetname")
168 42 : .metavar("<datasetname>")
169 21 : .store_into(psOptions->aosDatasetNames)
170 21 : .remaining()
171 21 : .help(_("Name(s) of the file(s) to delete."));
172 :
173 21 : deleteParser->add_argument("-f")
174 42 : .metavar("<format>")
175 21 : .store_into(psOptions->osDriverName)
176 : .help(
177 21 : _("Specify format of raster file if unknown by the application."));
178 :
179 42 : return argParser;
180 : }
181 :
182 : /************************************************************************/
183 : /* main() */
184 : /************************************************************************/
185 :
186 23 : MAIN_START(argc, argv)
187 :
188 : {
189 :
190 23 : EarlySetConfigOptions(argc, argv);
191 :
192 23 : argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
193 23 : if (argc < 1)
194 2 : exit(-argc);
195 :
196 : /* -------------------------------------------------------------------- */
197 : /* Parse arguments. */
198 : /* -------------------------------------------------------------------- */
199 :
200 21 : if (argc < 2)
201 : {
202 : try
203 : {
204 2 : GDALManageOptions sOptions;
205 1 : auto argParser = GDALManageAppOptionsGetParser(&sOptions);
206 1 : fprintf(stderr, "%s\n", argParser->usage().c_str());
207 : }
208 0 : catch (const std::exception &err)
209 : {
210 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
211 0 : err.what());
212 : }
213 1 : CSLDestroy(argv);
214 1 : exit(1);
215 : }
216 :
217 20 : GDALAllRegister();
218 :
219 20 : GDALManageOptions psOptions;
220 20 : auto argParser = GDALManageAppOptionsGetParser(&psOptions);
221 :
222 : try
223 : {
224 20 : argParser->parse_args_without_binary_name(argv + 1);
225 18 : CSLDestroy(argv);
226 : }
227 2 : catch (const std::exception &error)
228 : {
229 2 : argParser->display_error_and_usage(error);
230 2 : CSLDestroy(argv);
231 2 : exit(1);
232 : }
233 :
234 : // For some obscure reason datasetname is parsed as mandatory
235 : // if used with remaining() in a subparser
236 18 : if (psOptions.aosDatasetNames.empty() && psOptions.osDatasetName.empty())
237 : {
238 : std::invalid_argument error(
239 : _("No dataset name provided. At least one dataset "
240 1 : "name is required."));
241 1 : argParser->display_error_and_usage(error);
242 1 : exit(1);
243 : }
244 :
245 17 : GDALDriverH hDriver = nullptr;
246 17 : if (!psOptions.osDriverName.empty())
247 : {
248 2 : hDriver = GDALGetDriverByName(psOptions.osDriverName.c_str());
249 2 : if (hDriver == nullptr)
250 : {
251 1 : CPLError(CE_Failure, CPLE_AppDefined, "Failed to find driver '%s'.",
252 : psOptions.osDriverName.c_str());
253 1 : exit(1);
254 : }
255 : }
256 :
257 : /* -------------------------------------------------------------------- */
258 : /* Split out based on operation. */
259 : /* -------------------------------------------------------------------- */
260 :
261 16 : if (argParser->is_subcommand_used("identify"))
262 : {
263 : // Process all files in aosDatasetName
264 15 : for (const auto &datasetName : psOptions.aosDatasetNames)
265 : {
266 8 : ProcessIdentifyTarget(
267 8 : datasetName.c_str(), nullptr, psOptions.bRecursive,
268 8 : psOptions.bReportFailures, psOptions.bForceRecurse);
269 : }
270 : }
271 9 : else if (argParser->is_subcommand_used("copy"))
272 : {
273 6 : GDALCopyDatasetFiles(hDriver, psOptions.osNewName.c_str(),
274 : psOptions.osDatasetName.c_str());
275 : }
276 3 : else if (argParser->is_subcommand_used("rename"))
277 : {
278 1 : GDALRenameDataset(hDriver, psOptions.osNewName.c_str(),
279 : psOptions.osDatasetName.c_str());
280 : }
281 2 : else if (argParser->is_subcommand_used("delete"))
282 : {
283 : // Process all files in aosDatasetName
284 5 : for (const auto &datasetName : psOptions.aosDatasetNames)
285 : {
286 3 : GDALDeleteDataset(hDriver, datasetName.c_str());
287 : }
288 : }
289 :
290 : /* -------------------------------------------------------------------- */
291 : /* Cleanup */
292 : /* -------------------------------------------------------------------- */
293 16 : GDALDestroy();
294 :
295 16 : exit(0);
296 : }
297 :
298 0 : MAIN_END
|