LCOV - code coverage report
Current view: top level - apps - gdalmanage.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 122 127 96.1 %
Date: 2024-11-21 22:18:42 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         152 : 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         152 :     hDriver = GDALIdentifyDriver(pszTarget, papszSiblingList);
      51             : 
      52         152 :     if (hDriver != nullptr)
      53         119 :         printf("%s: %s\n", pszTarget, GDALGetDriverShortName(hDriver));
      54          33 :     else if (bReportFailures)
      55          11 :         printf("%s: unrecognized\n", pszTarget);
      56             : 
      57         152 :     if (!bForceRecurse && (!bRecursive || hDriver != nullptr))
      58         149 :         return;
      59             : 
      60         147 :     if (VSIStatL(pszTarget, &sStatBuf) != 0 || !VSI_ISDIR(sStatBuf.st_mode))
      61         144 :         return;
      62             : 
      63           3 :     papszSiblingList = VSIReadDir(pszTarget);
      64         153 :     for (i = 0; papszSiblingList && papszSiblingList[i]; i++)
      65             :     {
      66         150 :         if (EQUAL(papszSiblingList[i], "..") || EQUAL(papszSiblingList[i], "."))
      67           6 :             continue;
      68             : 
      69             :         CPLString osSubTarget =
      70         288 :             CPLFormFilename(pszTarget, papszSiblingList[i], nullptr);
      71             : 
      72         144 :         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          23 : GDALManageAppOptionsGetParser(GDALManageOptions *psOptions)
      84             : {
      85             :     auto argParser = std::make_unique<GDALArgumentParser>(
      86          23 :         "gdalmanage", /* bForBinary */ true);
      87             : 
      88          23 :     argParser->add_description(
      89          23 :         _("Identify, delete, rename and copy raster data files."));
      90          23 :     argParser->add_epilog(_("For more details, consult the full documentation "
      91             :                             "for the gdalmanage utility "
      92          23 :                             "https://gdal.org/programs/gdalmanage.html"));
      93             : 
      94         138 :     auto addCommonOptions = [psOptions](GDALArgumentParser *subParser)
      95             :     {
      96          46 :         subParser->add_argument("-f")
      97          92 :             .metavar("<format>")
      98          46 :             .store_into(psOptions->osDriverName)
      99             :             .help(_("Specify format of raster file if unknown by the "
     100          46 :                     "application."));
     101             : 
     102          46 :         subParser->add_argument("newdatasetname")
     103          92 :             .metavar("<newdatasetname>")
     104          46 :             .store_into(psOptions->osNewName)
     105          46 :             .help(_("Name of the new file."));
     106          46 :     };
     107             : 
     108             :     // Identify
     109             : 
     110             :     auto identifyParser =
     111          23 :         argParser->add_subparser("identify", /* bForBinary */ true);
     112          23 :     identifyParser->add_description(_("List data format of file(s)."));
     113             : 
     114          23 :     identifyParser->add_argument("-r")
     115          23 :         .flag()
     116          23 :         .store_into(psOptions->bRecursive)
     117          23 :         .help(_("Recursively scan files/folders for raster files."));
     118             : 
     119          23 :     identifyParser->add_argument("-fr")
     120          23 :         .flag()
     121          23 :         .store_into(psOptions->bRecursive)
     122          23 :         .store_into(psOptions->bForceRecurse)
     123             :         .help(_("Recursively scan folders for raster files, forcing "
     124          23 :                 "recursion in folders recognized as valid formats."));
     125             : 
     126          23 :     identifyParser->add_argument("-u")
     127          23 :         .flag()
     128          23 :         .store_into(psOptions->bReportFailures)
     129          23 :         .help(_("Report failures if file type is unidentified."));
     130             : 
     131             :     // Note: this accepts multiple files
     132          23 :     identifyParser->add_argument("datasetname")
     133          46 :         .metavar("<datasetname>")
     134          23 :         .store_into(psOptions->aosDatasetNames)
     135          23 :         .remaining()
     136          23 :         .help(_("Name(s) of the file(s) to identify."));
     137             : 
     138             :     // Copy
     139             : 
     140          23 :     auto copyParser = argParser->add_subparser("copy", /* bForBinary */ true);
     141             :     copyParser->add_description(
     142          23 :         _("Create a copy of the raster file with a new name."));
     143             : 
     144          23 :     addCommonOptions(copyParser);
     145             : 
     146          23 :     copyParser->add_argument("datasetname")
     147          46 :         .metavar("<datasetname>")
     148          23 :         .store_into(psOptions->osDatasetName)
     149          23 :         .help(_("Name of the file to copy."));
     150             : 
     151             :     // Rename
     152             : 
     153             :     auto renameParser =
     154          23 :         argParser->add_subparser("rename", /* bForBinary */ true);
     155          23 :     renameParser->add_description(_("Change the name of the raster file."));
     156             : 
     157          23 :     addCommonOptions(renameParser);
     158             : 
     159          23 :     renameParser->add_argument("datasetname")
     160          46 :         .metavar("<datasetname>")
     161          23 :         .store_into(psOptions->osDatasetName)
     162          23 :         .help(_("Name of the file to rename."));
     163             : 
     164             :     // Delete
     165             : 
     166             :     auto deleteParser =
     167          23 :         argParser->add_subparser("delete", /* bForBinary */ true);
     168          23 :     deleteParser->add_description(_("Delete the raster file(s)."));
     169             : 
     170             :     // Note: this accepts multiple files
     171          23 :     deleteParser->add_argument("datasetname")
     172          46 :         .metavar("<datasetname>")
     173          23 :         .store_into(psOptions->aosDatasetNames)
     174          23 :         .remaining()
     175          23 :         .help(_("Name(s) of the file(s) to delete."));
     176             : 
     177          23 :     deleteParser->add_argument("-f")
     178          46 :         .metavar("<format>")
     179          23 :         .store_into(psOptions->osDriverName)
     180             :         .help(
     181          23 :             _("Specify format of raster file if unknown by the application."));
     182             : 
     183          46 :     return argParser;
     184             : }
     185             : 
     186             : /************************************************************************/
     187             : /*                                main()                                */
     188             : /************************************************************************/
     189             : 
     190          23 : MAIN_START(argc, argv)
     191             : 
     192             : {
     193             : 
     194          23 :     EarlySetConfigOptions(argc, argv);
     195             : 
     196          23 :     argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
     197          23 :     if (argc < 1)
     198           0 :         exit(-argc);
     199             : 
     200             :     /* -------------------------------------------------------------------- */
     201             :     /*      Parse arguments.                                                */
     202             :     /* -------------------------------------------------------------------- */
     203             : 
     204          23 :     if (argc < 2)
     205             :     {
     206             :         try
     207             :         {
     208           2 :             GDALManageOptions sOptions;
     209           1 :             auto argParser = GDALManageAppOptionsGetParser(&sOptions);
     210           1 :             fprintf(stderr, "%s\n", argParser->usage().c_str());
     211             :         }
     212           0 :         catch (const std::exception &err)
     213             :         {
     214           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
     215           0 :                      err.what());
     216             :         }
     217           1 :         CSLDestroy(argv);
     218           1 :         exit(1);
     219             :     }
     220             : 
     221          22 :     GDALAllRegister();
     222             : 
     223          22 :     GDALManageOptions psOptions;
     224          22 :     auto argParser = GDALManageAppOptionsGetParser(&psOptions);
     225             : 
     226             :     try
     227             :     {
     228          22 :         argParser->parse_args_without_binary_name(argv + 1);
     229          18 :         CSLDestroy(argv);
     230             :     }
     231           2 :     catch (const std::exception &error)
     232             :     {
     233           2 :         argParser->display_error_and_usage(error);
     234           2 :         CSLDestroy(argv);
     235           2 :         exit(1);
     236             :     }
     237             : 
     238             :     // For some obscure reason datasetname is parsed as mandatory
     239             :     // if used with remaining() in a subparser
     240          18 :     if (psOptions.aosDatasetNames.empty() && psOptions.osDatasetName.empty())
     241             :     {
     242             :         std::invalid_argument error(
     243             :             _("No dataset name provided. At least one dataset "
     244           1 :               "name is required."));
     245           1 :         argParser->display_error_and_usage(error);
     246           1 :         exit(1);
     247             :     }
     248             : 
     249          17 :     GDALDriverH hDriver = nullptr;
     250          17 :     if (!psOptions.osDriverName.empty())
     251             :     {
     252           2 :         hDriver = GDALGetDriverByName(psOptions.osDriverName.c_str());
     253           2 :         if (hDriver == nullptr)
     254             :         {
     255           1 :             CPLError(CE_Failure, CPLE_AppDefined, "Failed to find driver '%s'.",
     256             :                      psOptions.osDriverName.c_str());
     257           1 :             exit(1);
     258             :         }
     259             :     }
     260             : 
     261             :     /* -------------------------------------------------------------------- */
     262             :     /*      Split out based on operation.                                   */
     263             :     /* -------------------------------------------------------------------- */
     264             : 
     265          16 :     if (argParser->is_subcommand_used("identify"))
     266             :     {
     267             :         // Process all files in aosDatasetName
     268          15 :         for (const auto &datasetName : psOptions.aosDatasetNames)
     269             :         {
     270           8 :             ProcessIdentifyTarget(
     271           8 :                 datasetName.c_str(), nullptr, psOptions.bRecursive,
     272           8 :                 psOptions.bReportFailures, psOptions.bForceRecurse);
     273             :         }
     274             :     }
     275           9 :     else if (argParser->is_subcommand_used("copy"))
     276             :     {
     277           6 :         GDALCopyDatasetFiles(hDriver, psOptions.osDatasetName.c_str(),
     278             :                              psOptions.osNewName.c_str());
     279             :     }
     280           3 :     else if (argParser->is_subcommand_used("rename"))
     281             :     {
     282           1 :         GDALRenameDataset(hDriver, psOptions.osDatasetName.c_str(),
     283             :                           psOptions.osNewName.c_str());
     284             :     }
     285           2 :     else if (argParser->is_subcommand_used("delete"))
     286             :     {
     287             :         // Process all files in aosDatasetName
     288           5 :         for (const auto &datasetName : psOptions.aosDatasetNames)
     289             :         {
     290           3 :             GDALDeleteDataset(hDriver, datasetName.c_str());
     291             :         }
     292             :     }
     293             : 
     294             :     /* -------------------------------------------------------------------- */
     295             :     /*      Cleanup                                                         */
     296             :     /* -------------------------------------------------------------------- */
     297          16 :     GDALDestroy();
     298             : 
     299          16 :     exit(0);
     300             : }
     301             : 
     302           0 : MAIN_END

Generated by: LCOV version 1.14