LCOV - code coverage report
Current view: top level - apps - gdalmanage.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 119 123 96.7 %
Date: 2025-05-15 18:21:54 Functions: 4 4 100.0 %

          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

Generated by: LCOV version 1.14