[Git][debian-gis-team/gdal-grass][master] 2 commits: Add upstream patch to fix FTBFS with GDAL 3.12.0. (closes: #1118730)
Bas Couwenberg (@sebastic)
gitlab at salsa.debian.org
Sat Oct 25 10:54:59 BST 2025
Bas Couwenberg pushed to branch master at Debian GIS Project / gdal-grass
Commits:
2c9240ab by Bas Couwenberg at 2025-10-25T11:48:06+02:00
Add upstream patch to fix FTBFS with GDAL 3.12.0. (closes: #1118730)
- - - - -
d7651cab by Bas Couwenberg at 2025-10-25T11:50:40+02:00
Set distribution to unstable.
- - - - -
3 changed files:
- debian/changelog
- + debian/patches/gdal-3.12.patch
- + debian/patches/series
Changes:
=====================================
debian/changelog
=====================================
@@ -1,9 +1,11 @@
-libgdal-grass (1:1.0.4-2) UNRELEASED; urgency=medium
+libgdal-grass (1:1.0.4-2) unstable; urgency=medium
* Update lintian overrides.
* Drop Rules-Requires-Root: no, default since dpkg 1.22.13.
+ * Add upstream patch to fix FTBFS with GDAL 3.12.0.
+ (closes: #1118730)
- -- Bas Couwenberg <sebastic at debian.org> Fri, 12 Sep 2025 17:36:50 +0200
+ -- Bas Couwenberg <sebastic at debian.org> Sat, 25 Oct 2025 11:50:27 +0200
libgdal-grass (1:1.0.4-1) unstable; urgency=medium
=====================================
debian/patches/gdal-3.12.patch
=====================================
@@ -0,0 +1,2282 @@
+Description: Fix FTBFS with GDAL 3.12.0.
+Author: Nicklas Larsson <n_larsson at yahoo.com>, Even Rouault <even.rouault at spatialys.com>
+Origin: https://github.com/OSGeo/gdal-grass/commits/main/
+Forwarded: not-needed
+
+--- a/grass.cpp
++++ b/grass.cpp
+@@ -30,7 +30,8 @@
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+-#include <stdlib.h>
++#include <array>
++#include <cstring>
+
+ #include "cpl_string.h"
+ #include "gdal_frmts.h"
+@@ -51,20 +52,23 @@ extern "C"
+ #include <grass/gprojects.h>
+ #include <grass/gis.h>
+
+- char *GPJ_grass_to_wkt(const struct Key_Value *, const struct Key_Value *,
+- int, int);
++ auto GPJ_grass_to_wkt(const struct Key_Value *, const struct Key_Value *,
++ int, int) -> char *;
+
+ void GDALRegister_GRASS();
+ }
+
+-#define GRASS_MAX_COLORS 100000 // what is the right value
++enum
++{
++ BUFF_SIZE = 200,
++ GRASS_MAX_COLORS = 100000
++};
+
+ /************************************************************************/
+ /* Grass2CPLErrorHook() */
+ /************************************************************************/
+
+-static int Grass2CPLErrorHook(char *pszMessage, int bFatal)
+-
++static auto Grass2CPLErrorHook(char *pszMessage, int bFatal) -> int
+ {
+ if (!bFatal)
+ //CPLDebug( "GRASS", "%s", pszMessage );
+@@ -76,6 +80,19 @@ static int Grass2CPLErrorHook(char *pszM
+ return 0;
+ }
+
++struct GRASSRasterPath
++{
++ std::string gisdbase;
++ std::string location;
++ std::string mapset;
++ std::string element;
++ std::string name;
++
++ explicit GRASSRasterPath(const char *path);
++ auto isValid() -> bool;
++ auto isCellHD() -> bool;
++};
++
+ /************************************************************************/
+ /* ==================================================================== */
+ /* GRASSDataset */
+@@ -88,27 +105,34 @@ class GRASSDataset final : public GDALDa
+ {
+ friend class GRASSRasterBand;
+
+- char *pszGisdbase;
+- char *pszLocation; /* LOCATION_NAME */
+- char *pszElement; /* cellhd or group */
++ std::string osGisdbase;
++ std::string osLocation; /* LOCATION_NAME */
++ std::string osElement; /* cellhd or group */
+
+- struct Cell_head sCellInfo; /* raster region */
++ struct Cell_head sCellInfo
++ {
++ }; /* raster region */
+
+ OGRSpatialReference m_oSRS{};
+
+- double adfGeoTransform[6];
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 12, 0)
++ GDALGeoTransform m_gt{};
++#else
++ std::array<double, 6> m_gt{0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
++#endif
+
+ public:
+- GRASSDataset();
+- ~GRASSDataset() override;
++ explicit GRASSDataset(GRASSRasterPath &);
+
+- const OGRSpatialReference *GetSpatialRef() const override;
+- CPLErr GetGeoTransform(double *) override;
++ auto GetSpatialRef() const -> const OGRSpatialReference * override;
+
+- static GDALDataset *Open(GDALOpenInfo *);
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 12, 0)
++ auto GetGeoTransform(GDALGeoTransform &) const -> CPLErr override;
++#else
++ auto GetGeoTransform(double *) -> CPLErr override;
++#endif
+
+- private:
+- static bool SplitPath(char *, char **, char **, char **, char **, char **);
++ static auto Open(GDALOpenInfo *) -> GDALDataset *;
+ };
+
+ /************************************************************************/
+@@ -121,74 +145,76 @@ class GRASSRasterBand final : public GDA
+ {
+ friend class GRASSDataset;
+
+- char *pszCellName;
+- char *pszMapset;
++ std::string osCellName;
++ std::string osMapset;
+ int hCell;
+ int nGRSType; // GRASS raster type: CELL_TYPE, FCELL_TYPE, DCELL_TYPE
+ bool nativeNulls; // use GRASS native NULL values
+
+- struct Colors sGrassColors;
++ struct Colors sGrassColors
++ {
++ };
+ GDALColorTable *poCT;
+
+- struct Cell_head sOpenWindow; /* the region when the raster was opened */
++ struct Cell_head sOpenWindow
++ {
++ }; /* the region when the raster was opened */
+
+ int bHaveMinMax;
+- double dfCellMin;
+- double dfCellMax;
++ double dfCellMin{0.0};
++ double dfCellMax{0.0};
+
+ double dfNoData;
+
+- bool valid;
++ bool valid{false};
+
+ public:
+- GRASSRasterBand(GRASSDataset *, int, const char *, const char *);
++ GRASSRasterBand(GRASSDataset *, int, std::string &, std::string &);
+ ~GRASSRasterBand() override;
+
+- CPLErr IReadBlock(int, int, void *) override;
+- CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
+- GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace,
+- GDALRasterIOExtraArg *psExtraArg) override;
+- GDALColorInterp GetColorInterpretation() override;
+- GDALColorTable *GetColorTable() override;
+- double GetMinimum(int *pbSuccess = NULL) override;
+- double GetMaximum(int *pbSuccess = NULL) override;
+- double GetNoDataValue(int *pbSuccess = NULL) override;
++ auto IReadBlock(int, int, void *) -> CPLErr override;
++ auto IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
++ GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace,
++ GDALRasterIOExtraArg *psExtraArg) -> CPLErr override;
++ auto GetColorInterpretation() -> GDALColorInterp override;
++ auto GetColorTable() -> GDALColorTable * override;
++ auto GetMinimum(int *pbSuccess = nullptr) -> double override;
++ auto GetMaximum(int *pbSuccess = nullptr) -> double override;
++ auto GetNoDataValue(int *pbSuccess = nullptr) -> double override;
+
+ private:
+ void SetWindow(struct Cell_head *);
+- CPLErr ResetReading(struct Cell_head *);
++ auto ResetReading(struct Cell_head *) -> CPLErr;
+ };
+
+ /************************************************************************/
+ /* GRASSRasterBand() */
+ /************************************************************************/
+-
+ GRASSRasterBand::GRASSRasterBand(GRASSDataset *poDSIn, int nBandIn,
+- const char *pszMapsetIn,
+- const char *pszCellNameIn)
+-
++ std::string &pszMapsetIn,
++ std::string &pszCellNameIn)
++ : osCellName(pszCellNameIn), osMapset(pszMapsetIn),
++ nGRSType(Rast_map_type(osCellName.c_str(), osMapset.c_str()))
+ {
+- struct Cell_head sCellInfo;
++ struct Cell_head sCellInfo
++ {
++ };
+
+ // Note: GISDBASE, LOCATION_NAME ans MAPSET was set in GRASSDataset::Open
+
+ this->poDS = poDSIn;
+ this->nBand = nBandIn;
+- this->valid = false;
+
+- this->pszCellName = G_store((char *)pszCellNameIn);
+- this->pszMapset = G_store((char *)pszMapsetIn);
+-
+- Rast_get_cellhd((char *)pszCellName, (char *)pszMapset, &sCellInfo);
+- nGRSType = Rast_map_type((char *)pszCellName, (char *)pszMapset);
++ Rast_get_cellhd(osCellName.c_str(), osMapset.c_str(), &sCellInfo);
+
+ /* -------------------------------------------------------------------- */
+ /* Get min/max values. */
+ /* -------------------------------------------------------------------- */
+- struct FPRange sRange;
++ struct FPRange sRange
++ {
++ };
+
+- if (Rast_read_fp_range((char *)pszCellName, (char *)pszMapset, &sRange) ==
+- -1)
++ if (Rast_read_fp_range(osCellName.c_str(), osMapset.c_str(), &sRange) == -1)
+ {
+ bHaveMinMax = FALSE;
+ }
+@@ -242,7 +268,7 @@ GRASSRasterBand::GRASSRasterBand(GRASSDa
+ }
+ else
+ { // maximum is not known or full range is used
+- CELL cval;
++ CELL cval = 0;
+ this->eDataType = GDT_Int32;
+ Rast_set_c_null_value(&cval, 1);
+ dfNoData = (double)cval;
+@@ -251,7 +277,7 @@ GRASSRasterBand::GRASSRasterBand(GRASSDa
+ }
+ else
+ { // 3-4 bytes
+- CELL cval;
++ CELL cval = 0;
+ this->eDataType = GDT_Int32;
+ Rast_set_c_null_value(&cval, 1);
+ dfNoData = (double)cval;
+@@ -260,7 +286,7 @@ GRASSRasterBand::GRASSRasterBand(GRASSDa
+ }
+ else if (nGRSType == FCELL_TYPE)
+ {
+- FCELL fval;
++ FCELL fval = NAN;
+ this->eDataType = GDT_Float32;
+ Rast_set_f_null_value(&fval, 1);
+ dfNoData = (double)fval;
+@@ -268,7 +294,7 @@ GRASSRasterBand::GRASSRasterBand(GRASSDa
+ }
+ else if (nGRSType == DCELL_TYPE)
+ {
+- DCELL dval;
++ DCELL dval = NAN;
+ this->eDataType = GDT_Float64;
+ Rast_set_d_null_value(&dval, 1);
+ dfNoData = (double)dval;
+@@ -281,18 +307,18 @@ GRASSRasterBand::GRASSRasterBand(GRASSDa
+ Rast_set_window(&(poDSIn->sCellInfo));
+ // open the raster only for actual reading
+ hCell = -1;
+- memcpy((void *)&sOpenWindow, (void *)&(poDSIn->sCellInfo),
+- sizeof(struct Cell_head));
++ memcpy(static_cast<void *>(&sOpenWindow),
++ static_cast<void *>(&(poDSIn->sCellInfo)), sizeof(struct Cell_head));
+
+ /* -------------------------------------------------------------------- */
+ /* Do we have a color table? */
+ /* -------------------------------------------------------------------- */
+- poCT = NULL;
+- if (Rast_read_colors((char *)pszCellName, (char *)pszMapset,
+- &sGrassColors) == 1)
++ poCT = nullptr;
++ if (Rast_read_colors(osCellName.c_str(), osMapset.c_str(), &sGrassColors) ==
++ 1)
+ {
+- int maxcolor;
+- CELL min, max;
++ int maxcolor = 0;
++ CELL min = 0, max = 0;
+
+ Rast_get_c_color_range(&min, &max, &sGrassColors);
+
+@@ -332,15 +358,15 @@ GRASSRasterBand::GRASSRasterBand(GRASSDa
+ poCT = new GDALColorTable();
+ for (int iColor = 0; iColor <= maxcolor; iColor++)
+ {
+- int nRed, nGreen, nBlue;
++ int nRed = 0, nGreen = 0, nBlue = 0;
+ GDALColorEntry sColor;
+
+ if (Rast_get_c_color(&iColor, &nRed, &nGreen, &nBlue,
+ &sGrassColors))
+ {
+- sColor.c1 = nRed;
+- sColor.c2 = nGreen;
+- sColor.c3 = nBlue;
++ sColor.c1 = (short)nRed;
++ sColor.c2 = (short)nGreen;
++ sColor.c3 = (short)nBlue;
+ sColor.c4 = 255;
+
+ poCT->SetColorEntry(iColor, &sColor);
+@@ -357,26 +383,28 @@ GRASSRasterBand::GRASSRasterBand(GRASSDa
+ }
+
+ /* Create metadata entries for color table rules */
+- char key[200], value[200];
++ std::array<char, BUFF_SIZE> value{};
++ std::array<char, BUFF_SIZE> key{};
+ int rcount = Rast_colors_count(&sGrassColors);
+
+- snprintf(value, sizeof(value), "%d", rcount);
+- this->SetMetadataItem("COLOR_TABLE_RULES_COUNT", value);
++ (void)std::snprintf(value.data(), BUFF_SIZE, "%d", rcount);
++ this->SetMetadataItem("COLOR_TABLE_RULES_COUNT", value.data());
+
+ /* Add the rules in reverse order */
+ for (int i = rcount - 1; i >= 0; i--)
+ {
+- DCELL val1, val2;
+- unsigned char r1, g1, b1, r2, g2, b2;
++ DCELL val1 = NAN, val2 = NAN;
++ unsigned char r1 = 0, g1 = 0, b1 = 0, r2 = 0, g2 = 0, b2 = 0;
+
+ Rast_get_fp_color_rule(&val1, &r1, &g1, &b1, &val2, &r2, &g2, &b2,
+ &sGrassColors, i);
+
+- snprintf(key, sizeof(key), "COLOR_TABLE_RULE_RGB_%d",
+- rcount - i - 1);
+- snprintf(value, sizeof(value), "%e %e %d %d %d %d %d %d", val1,
+- val2, r1, g1, b1, r2, g2, b2);
+- this->SetMetadataItem(key, value);
++ (void)std::snprintf(key.data(), key.size(),
++ "COLOR_TABLE_RULE_RGB_%d", rcount - i - 1);
++ (void)std::snprintf(value.data(), value.size(),
++ "%e %e %d %d %d %d %d %d", val1, val2, r1, g1,
++ b1, r2, g2, b2);
++ this->SetMetadataItem(key.data(), value.data());
+ }
+ }
+ else
+@@ -393,7 +421,7 @@ GRASSRasterBand::GRASSRasterBand(GRASSDa
+
+ GRASSRasterBand::~GRASSRasterBand()
+ {
+- if (poCT != NULL)
++ if (poCT != nullptr)
+ {
+ Rast_free_colors(&sGrassColors);
+ delete poCT;
+@@ -401,12 +429,6 @@ GRASSRasterBand::~GRASSRasterBand()
+
+ if (hCell >= 0)
+ Rast_close(hCell);
+-
+- if (pszCellName)
+- G_free(pszCellName);
+-
+- if (pszMapset)
+- G_free(pszMapset);
+ }
+
+ /************************************************************************/
+@@ -430,11 +452,13 @@ void GRASSRasterBand::SetWindow(struct C
+ Rast_set_window(sNewWindow);
+
+ /* Set GRASS env to the current raster, don't open the raster */
+- G_setenv_nogisrc("GISDBASE", ((GRASSDataset *)poDS)->pszGisdbase);
+- G_setenv_nogisrc("LOCATION_NAME", ((GRASSDataset *)poDS)->pszLocation);
+- G_setenv_nogisrc("MAPSET", pszMapset);
++ G_setenv_nogisrc("GISDBASE",
++ (dynamic_cast<GRASSDataset *>(poDS))->osGisdbase.c_str());
++ G_setenv_nogisrc("LOCATION_NAME",
++ (dynamic_cast<GRASSDataset *>(poDS))->osLocation.c_str());
++ G_setenv_nogisrc("MAPSET", osMapset.c_str());
+ G_reset_mapsets();
+- G_add_mapset_to_search_path(pszMapset);
++ G_add_mapset_to_search_path(osMapset.c_str());
+ }
+
+ /************************************************************************/
+@@ -445,7 +469,7 @@ void GRASSRasterBand::SetWindow(struct C
+ /* */
+ /* Returns CE_Failure if fails, otherwise CE_None */
+ /************************************************************************/
+-CPLErr GRASSRasterBand::ResetReading(struct Cell_head *sNewWindow)
++auto GRASSRasterBand::ResetReading(struct Cell_head *sNewWindow) -> CPLErr
+ {
+
+ /* Check if the window has changed */
+@@ -459,13 +483,15 @@ CPLErr GRASSRasterBand::ResetReading(str
+ sNewWindow->cols != sOpenWindow.cols)
+ {
+ SetWindow(sNewWindow);
+- memcpy((void *)&sOpenWindow, (void *)sNewWindow,
+- sizeof(struct Cell_head));
++ memcpy(static_cast<void *>(&sOpenWindow),
++ static_cast<void *>(sNewWindow), sizeof(struct Cell_head));
+ }
+ else
+ {
+ /* The windows are identical, check current window */
+- struct Cell_head sCurrentWindow;
++ struct Cell_head sCurrentWindow
++ {
++ };
+
+ Rast_get_window(&sCurrentWindow);
+
+@@ -490,25 +516,26 @@ CPLErr GRASSRasterBand::ResetReading(str
+ /* */
+ /************************************************************************/
+
+-CPLErr GRASSRasterBand::IReadBlock(int /*nBlockXOff*/, int nBlockYOff,
+- void *pImage)
+-
++auto GRASSRasterBand::IReadBlock(int /*nBlockXOff*/, int nBlockYOff,
++ void *pImage) -> CPLErr
+ {
+ if (!this->valid)
+ return CE_Failure;
+
+ // Reset window because IRasterIO could be previously called.
+- if (ResetReading(&(((GRASSDataset *)poDS)->sCellInfo)) != CE_None)
++ if (ResetReading(&((dynamic_cast<GRASSDataset *>(poDS))->sCellInfo)) !=
++ CE_None)
+ {
+ return CE_Failure;
+ }
+ // open for reading
+ if (hCell < 0)
+ {
+- if ((hCell = Rast_open_old((char *)pszCellName, (char *)pszMapset)) < 0)
++ hCell = Rast_open_old(osCellName.c_str(), osMapset.c_str());
++ if (hCell < 0)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+- "GRASS: Cannot open raster '%s'", pszCellName);
++ "GRASS: Cannot open raster '%s'", osCellName.c_str());
+ return CE_Failure;
+ }
+ }
+@@ -525,22 +552,23 @@ CPLErr GRASSRasterBand::IReadBlock(int /
+ cbuf[col] = (CELL)dfNoData;
+ }
+
+- GDALCopyWords((void *)cbuf, GDT_Int32, sizeof(CELL), pImage, eDataType,
+- GDALGetDataTypeSize(eDataType) / 8, nBlockXSize);
++ GDALCopyWords(static_cast<void *>(cbuf), GDT_Int32, sizeof(CELL),
++ pImage, eDataType, GDALGetDataTypeSizeBytes(eDataType),
++ nBlockXSize);
+
+ G_free(cbuf);
+ }
+ else if (eDataType == GDT_Int32)
+ {
+- Rast_get_c_row(hCell, (CELL *)pImage, nBlockYOff);
++ Rast_get_c_row(hCell, static_cast<CELL *>(pImage), nBlockYOff);
+ }
+ else if (eDataType == GDT_Float32)
+ {
+- Rast_get_f_row(hCell, (FCELL *)pImage, nBlockYOff);
++ Rast_get_f_row(hCell, static_cast<FCELL *>(pImage), nBlockYOff);
+ }
+ else if (eDataType == GDT_Float64)
+ {
+- Rast_get_d_row(hCell, (DCELL *)pImage, nBlockYOff);
++ Rast_get_d_row(hCell, static_cast<DCELL *>(pImage), nBlockYOff);
+ }
+
+ // close to avoid confusion with other GRASS raster bands
+@@ -555,26 +583,28 @@ CPLErr GRASSRasterBand::IReadBlock(int /
+ /* */
+ /************************************************************************/
+
+-CPLErr GRASSRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
+- int nXSize, int nYSize, void *pData,
+- int nBufXSize, int nBufYSize,
+- GDALDataType eBufType, GSpacing nPixelSpace,
+- GSpacing nLineSpace,
+- GDALRasterIOExtraArg * /*psExtraArg*/)
++auto GRASSRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
++ int nXSize, int nYSize, void *pData,
++ int nBufXSize, int nBufYSize,
++ GDALDataType eBufType, GSpacing nPixelSpace,
++ GSpacing nLineSpace,
++ GDALRasterIOExtraArg * /*psExtraArg*/) -> CPLErr
+ {
+ /* GRASS library does that, we have only calculate and reset the region in map units
+ * and if the region has changed, reopen the raster */
+
+ /* Calculate the region */
+- struct Cell_head sWindow;
+- struct Cell_head *psDsWindow;
++ struct Cell_head sWindow
++ {
++ };
++ struct Cell_head *psDsWindow = nullptr;
+
+ if (eRWFlag != GF_Read)
+ return CE_Failure;
+ if (!this->valid)
+ return CE_Failure;
+
+- psDsWindow = &(((GRASSDataset *)poDS)->sCellInfo);
++ psDsWindow = &((dynamic_cast<GRASSDataset *>(poDS))->sCellInfo);
+
+ sWindow.north = psDsWindow->north - nYOff * psDsWindow->ns_res;
+ sWindow.south = sWindow.north - nYSize * psDsWindow->ns_res;
+@@ -596,23 +626,24 @@ CPLErr GRASSRasterBand::IRasterIO(GDALRW
+ // open for reading
+ if (hCell < 0)
+ {
+- if ((hCell = Rast_open_old((char *)pszCellName, (char *)pszMapset)) < 0)
++ hCell = Rast_open_old(osCellName.c_str(), osMapset.c_str());
++ if (hCell < 0)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+- "GRASS: Cannot open raster '%s'", pszCellName);
++ "GRASS: Cannot open raster '%s'", osCellName.c_str());
+ return CE_Failure;
+ }
+ }
+
+ /* Read Data */
+- CELL *cbuf = NULL;
+- FCELL *fbuf = NULL;
+- DCELL *dbuf = NULL;
++ CELL *cbuf = nullptr;
++ FCELL *fbuf = nullptr;
++ DCELL *dbuf = nullptr;
+ bool direct = false;
+
+ /* Reset space if default (0) */
+ if (nPixelSpace == 0)
+- nPixelSpace = GDALGetDataTypeSize(eBufType) / 8;
++ nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
+
+ if (nLineSpace == 0)
+ nLineSpace = nBufXSize * nPixelSpace;
+@@ -640,55 +671,58 @@ CPLErr GRASSRasterBand::IRasterIO(GDALRW
+
+ for (int row = 0; row < nBufYSize; row++)
+ {
+- char *pnt = (char *)pData + row * nLineSpace;
++ char *pnt = static_cast<char *>(pData) + row * nLineSpace;
+
+ if (nGRSType == CELL_TYPE)
+ {
+ if (direct)
+ {
+- Rast_get_c_row(hCell, (CELL *)pnt, row);
++ Rast_get_c_row(hCell, reinterpret_cast<CELL *>(pnt), row);
+ }
+ else
+ {
+ Rast_get_c_row(hCell, cbuf, row);
+
+- /* Reset NULLs */
++ /* Reset nullptrs */
+ for (int col = 0; col < nBufXSize; col++)
+ {
+ if (Rast_is_c_null_value(&(cbuf[col])))
+ cbuf[col] = (CELL)dfNoData;
+ }
+
+- GDALCopyWords((void *)cbuf, GDT_Int32, sizeof(CELL),
+- (void *)pnt, eBufType, nPixelSpace, nBufXSize);
++ GDALCopyWords(static_cast<void *>(cbuf), GDT_Int32,
++ sizeof(CELL), static_cast<void *>(pnt), eBufType,
++ (int)nPixelSpace, nBufXSize);
+ }
+ }
+ else if (nGRSType == FCELL_TYPE)
+ {
+ if (direct)
+ {
+- Rast_get_f_row(hCell, (FCELL *)pnt, row);
++ Rast_get_f_row(hCell, reinterpret_cast<FCELL *>(pnt), row);
+ }
+ else
+ {
+ Rast_get_f_row(hCell, fbuf, row);
+
+- GDALCopyWords((void *)fbuf, GDT_Float32, sizeof(FCELL),
+- (void *)pnt, eBufType, nPixelSpace, nBufXSize);
++ GDALCopyWords(static_cast<void *>(fbuf), GDT_Float32,
++ sizeof(FCELL), static_cast<void *>(pnt), eBufType,
++ (int)nPixelSpace, nBufXSize);
+ }
+ }
+ else if (nGRSType == DCELL_TYPE)
+ {
+ if (direct)
+ {
+- Rast_get_d_row(hCell, (DCELL *)pnt, row);
++ Rast_get_d_row(hCell, reinterpret_cast<DCELL *>(pnt), row);
+ }
+ else
+ {
+ Rast_get_d_row(hCell, dbuf, row);
+
+- GDALCopyWords((void *)dbuf, GDT_Float64, sizeof(DCELL),
+- (void *)pnt, eBufType, nPixelSpace, nBufXSize);
++ GDALCopyWords(static_cast<void *>(dbuf), GDT_Float64,
++ sizeof(DCELL), static_cast<void *>(pnt), eBufType,
++ (int)nPixelSpace, nBufXSize);
+ }
+ }
+ }
+@@ -711,10 +745,9 @@ CPLErr GRASSRasterBand::IRasterIO(GDALRW
+ /* GetColorInterpretation() */
+ /************************************************************************/
+
+-GDALColorInterp GRASSRasterBand::GetColorInterpretation()
+-
++auto GRASSRasterBand::GetColorInterpretation() -> GDALColorInterp
+ {
+- if (poCT != NULL)
++ if (poCT != nullptr)
+ return GCI_PaletteIndex;
+ else
+ return GCI_GrayIndex;
+@@ -724,8 +757,7 @@ GDALColorInterp GRASSRasterBand::GetColo
+ /* GetColorTable() */
+ /************************************************************************/
+
+-GDALColorTable *GRASSRasterBand::GetColorTable()
+-
++auto GRASSRasterBand::GetColorTable() -> GDALColorTable *
+ {
+ return poCT;
+ }
+@@ -734,8 +766,7 @@ GDALColorTable *GRASSRasterBand::GetColo
+ /* GetMinimum() */
+ /************************************************************************/
+
+-double GRASSRasterBand::GetMinimum(int *pbSuccess)
+-
++auto GRASSRasterBand::GetMinimum(int *pbSuccess) -> double
+ {
+ if (pbSuccess)
+ *pbSuccess = bHaveMinMax;
+@@ -753,8 +784,7 @@ double GRASSRasterBand::GetMinimum(int *
+ /* GetMaximum() */
+ /************************************************************************/
+
+-double GRASSRasterBand::GetMaximum(int *pbSuccess)
+-
++auto GRASSRasterBand::GetMaximum(int *pbSuccess) -> double
+ {
+ if (pbSuccess)
+ *pbSuccess = bHaveMinMax;
+@@ -762,9 +792,8 @@ double GRASSRasterBand::GetMaximum(int *
+ if (bHaveMinMax)
+ return dfCellMax;
+
+- else if (eDataType == GDT_Float32 || eDataType == GDT_Float64)
+- return 4294967295.0;
+- else if (eDataType == GDT_UInt32)
++ else if (eDataType == GDT_Float32 || eDataType == GDT_Float64 ||
++ eDataType == GDT_UInt32)
+ return 4294967295.0;
+ else if (eDataType == GDT_UInt16)
+ return 65535;
+@@ -776,8 +805,7 @@ double GRASSRasterBand::GetMaximum(int *
+ /* GetNoDataValue() */
+ /************************************************************************/
+
+-double GRASSRasterBand::GetNoDataValue(int *pbSuccess)
+-
++auto GRASSRasterBand::GetNoDataValue(int *pbSuccess) -> double
+ {
+ if (pbSuccess)
+ *pbSuccess = TRUE;
+@@ -795,43 +823,18 @@ double GRASSRasterBand::GetNoDataValue(i
+ /* GRASSDataset() */
+ /************************************************************************/
+
+-GRASSDataset::GRASSDataset()
++GRASSDataset::GRASSDataset(GRASSRasterPath &gpath)
++ : osGisdbase(gpath.gisdbase), osLocation(gpath.location),
++ osElement(gpath.element)
+ {
+ m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
+-
+- adfGeoTransform[0] = 0.0;
+- adfGeoTransform[1] = 1.0;
+- adfGeoTransform[2] = 0.0;
+- adfGeoTransform[3] = 0.0;
+- adfGeoTransform[4] = 0.0;
+- adfGeoTransform[5] = 1.0;
+- pszGisdbase = NULL;
+- pszLocation = NULL;
+- pszElement = NULL;
+-}
+-
+-/************************************************************************/
+-/* ~GRASSDataset() */
+-/************************************************************************/
+-
+-GRASSDataset::~GRASSDataset()
+-{
+-
+- if (pszGisdbase)
+- G_free(pszGisdbase);
+-
+- if (pszLocation)
+- G_free(pszLocation);
+-
+- if (pszElement)
+- G_free(pszElement);
+ }
+
+ /************************************************************************/
+ /* GetSpatialRef() */
+ /************************************************************************/
+
+-const OGRSpatialReference *GRASSDataset::GetSpatialRef() const
++auto GRASSDataset::GetSpatialRef() const -> const OGRSpatialReference *
+ {
+ return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
+ }
+@@ -840,88 +843,40 @@ const OGRSpatialReference *GRASSDataset:
+ /* GetGeoTransform() */
+ /************************************************************************/
+
+-CPLErr GRASSDataset::GetGeoTransform(double *padfGeoTransform)
++
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 12, 0)
++auto GRASSDataset::GetGeoTransform(GDALGeoTransform >) const -> CPLErr
+ {
+- memcpy(padfGeoTransform, adfGeoTransform, sizeof(double) * 6);
++ gt = m_gt;
+
+ return CE_None;
+ }
+-
+-/************************************************************************/
+-/* SplitPath() */
+-/* Split full path to cell or group to: */
+-/* gisdbase, location, mapset, element, name */
+-/* New string are allocated and should be freed when no longer needed. */
+-/* */
+-/* Returns: true - OK */
+-/* false - failed */
+-/************************************************************************/
+-bool GRASSDataset::SplitPath(char *path, char **gisdbase, char **location,
+- char **mapset, char **element, char **name)
++#else
++auto GRASSDataset::GetGeoTransform(double *padfGeoTransform) -> CPLErr
+ {
+- char *p;
+- char *ptr[5];
+- char *tmp;
+- int i = 0;
+-
+- *gisdbase = NULL;
+- *location = NULL;
+- *mapset = NULL;
+- *element = NULL;
+- *name = NULL;
+-
+- if (!path || strlen(path) == 0)
+- return false;
+-
+- tmp = G_store(path);
+-
+- while ((p = strrchr(tmp, '/')) != NULL && i < 4)
+- {
+- *p = '\0';
+-
+- if (strlen(p + 1) == 0) /* repeated '/' */
+- continue;
+-
+- ptr[i++] = p + 1;
+- }
++ memcpy(padfGeoTransform, m_gt.data(), sizeof(double) * 6);
+
+- /* Note: empty GISDBASE == 0 is not accepted (relative path) */
+- if (i != 4)
+- {
+- G_free(tmp);
+- return false;
+- }
+-
+- *gisdbase = G_store(tmp);
+- *location = G_store(ptr[3]);
+- *mapset = G_store(ptr[2]);
+- *element = G_store(ptr[1]);
+- *name = G_store(ptr[0]);
+-
+- G_free(tmp);
+- return true;
++ return CE_None;
+ }
++#endif
+
+ /************************************************************************/
+ /* Open() */
+ /************************************************************************/
+
+-typedef int (*GrassErrorHandler)(const char *, int);
+-
+-GDALDataset *GRASSDataset::Open(GDALOpenInfo *poOpenInfo)
++using GrassErrorHandler = auto(*)(const char *, int) -> int;
+
++auto GRASSDataset::Open(GDALOpenInfo *poOpenInfo) -> GDALDataset *
+ {
+- char *pszGisdb = NULL, *pszLoc = NULL;
+- char *pszMapset = NULL, *pszElem = NULL, *pszName = NULL;
+- char **papszCells = NULL;
+- char **papszMapsets = NULL;
++ char **papszCells = nullptr;
++ char **papszMapsets = nullptr;
+
+ /* -------------------------------------------------------------------- */
+ /* Does this even look like a grass file path? */
+ /* -------------------------------------------------------------------- */
+- if (strstr(poOpenInfo->pszFilename, "/cellhd/") == NULL &&
+- strstr(poOpenInfo->pszFilename, "/group/") == NULL)
+- return NULL;
++ if (strstr(poOpenInfo->pszFilename, "/cellhd/") == nullptr &&
++ strstr(poOpenInfo->pszFilename, "/group/") == nullptr)
++ return nullptr;
+
+ /* Always init, if no rasters are opened G_no_gisinit resets the projection and
+ * rasters in different projection may be then opened */
+@@ -933,91 +888,83 @@ GDALDataset *GRASSDataset::Open(GDALOpen
+ G_no_gisinit(); // Doesn't check write permissions for mapset compare to G_gisinit
+
+ // Set error function
+- G_set_error_routine((GrassErrorHandler)Grass2CPLErrorHook);
++ G_set_error_routine(GrassErrorHandler(Grass2CPLErrorHook));
+
+ // GISBASE is path to the directory where GRASS is installed,
+ if (!getenv("GISBASE"))
+ {
+- static char *gisbaseEnv = NULL;
++ static char *gisbaseEnv = nullptr;
+ const char *gisbase = GRASS_GISBASE;
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "GRASS warning: GISBASE "
+ "environment variable was not set, using:\n%s",
+ gisbase);
+- char buf[2000];
+- snprintf(buf, sizeof(buf), "GISBASE=%s", gisbase);
+- buf[sizeof(buf) - 1] = '\0';
++ std::array<char, BUFF_SIZE> buf{};
++ int res = std::snprintf(buf.data(), BUFF_SIZE, "GISBASE=%s", gisbase);
++ if (res >= BUFF_SIZE)
++ {
++ CPLError(
++ CE_Warning, CPLE_AppDefined,
++ "GRASS warning: GISBASE environment variable was too long.\n");
++ return nullptr;
++ }
+
+ CPLFree(gisbaseEnv);
+- gisbaseEnv = CPLStrdup(buf);
++ gisbaseEnv = CPLStrdup(buf.data());
+ putenv(gisbaseEnv);
+ }
+
+- if (!SplitPath(poOpenInfo->pszFilename, &pszGisdb, &pszLoc, &pszMapset,
+- &pszElem, &pszName))
+- {
+- return NULL;
+- }
++ GRASSRasterPath gp = GRASSRasterPath(poOpenInfo->pszFilename);
+
+ /* -------------------------------------------------------------------- */
+ /* Check element name */
+ /* -------------------------------------------------------------------- */
+- if (strcmp(pszElem, "cellhd") != 0 && strcmp(pszElem, "group") != 0)
++ if (!gp.isValid())
+ {
+- G_free(pszGisdb);
+- G_free(pszLoc);
+- G_free(pszMapset);
+- G_free(pszElem);
+- G_free(pszName);
+- return NULL;
++ return nullptr;
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Set GRASS variables */
+ /* -------------------------------------------------------------------- */
+
+- G_setenv_nogisrc("GISDBASE", pszGisdb);
+- G_setenv_nogisrc("LOCATION_NAME", pszLoc);
+- G_setenv_nogisrc("MAPSET",
+- pszMapset); // group is searched only in current mapset
++ G_setenv_nogisrc("GISDBASE", gp.gisdbase.c_str());
++ G_setenv_nogisrc("LOCATION_NAME", gp.location.c_str());
++ G_setenv_nogisrc(
++ "MAPSET",
++ gp.mapset.c_str()); // group is searched only in current mapset
+ G_reset_mapsets();
+- G_add_mapset_to_search_path(pszMapset);
++ G_add_mapset_to_search_path(gp.mapset.c_str());
+
+ /* -------------------------------------------------------------------- */
+ /* Check if this is a valid grass cell. */
+ /* -------------------------------------------------------------------- */
+- if (strcmp(pszElem, "cellhd") == 0)
++ if (gp.isCellHD())
+ {
+
+- if (G_find_file2("cell", pszName, pszMapset) == NULL)
++ if (G_find_file2("cell", gp.name.c_str(), gp.mapset.c_str()) == nullptr)
+ {
+- G_free(pszGisdb);
+- G_free(pszLoc);
+- G_free(pszMapset);
+- G_free(pszElem);
+- G_free(pszName);
+- return NULL;
++ return nullptr;
+ }
+
+- papszMapsets = CSLAddString(papszMapsets, pszMapset);
+- papszCells = CSLAddString(papszCells, pszName);
++ papszMapsets = CSLAddString(papszMapsets, gp.mapset.c_str());
++ papszCells = CSLAddString(papszCells, gp.name.c_str());
+ }
++
+ /* -------------------------------------------------------------------- */
+ /* Check if this is a valid GRASS imagery group. */
+ /* -------------------------------------------------------------------- */
+ else
+ {
+- struct Ref ref;
++ struct Ref ref
++ {
++ };
+
+ I_init_group_ref(&ref);
+- if (I_get_group_ref(pszName, &ref) == 0)
++ bool has_group_ref = I_get_group_ref(gp.name.c_str(), &ref);
++ if (!has_group_ref || ref.nfiles <= 0)
+ {
+- G_free(pszGisdb);
+- G_free(pszLoc);
+- G_free(pszMapset);
+- G_free(pszElem);
+- G_free(pszName);
+- return NULL;
++ return nullptr;
+ }
+
+ for (int iRef = 0; iRef < ref.nfiles; iRef++)
+@@ -1030,20 +977,18 @@ GDALDataset *GRASSDataset::Open(GDALOpen
+ I_free_group_ref(&ref);
+ }
+
+- G_free(pszMapset);
+- G_free(pszName);
+-
+ /* -------------------------------------------------------------------- */
+ /* Create a corresponding GDALDataset. */
+ /* -------------------------------------------------------------------- */
+- GRASSDataset *poDS = new GRASSDataset();
++ auto poDS = new GRASSDataset(gp);
+
+ /* notdef: should only allow read access to an existing cell, right? */
+ poDS->eAccess = poOpenInfo->eAccess;
+
+- poDS->pszGisdbase = pszGisdb;
+- poDS->pszLocation = pszLoc;
+- poDS->pszElement = pszElem;
++ if (!papszCells)
++ {
++ return nullptr;
++ }
+
+ /* -------------------------------------------------------------------- */
+ /* Capture some information from the file that is of interest. */
+@@ -1054,20 +999,19 @@ GDALDataset *GRASSDataset::Open(GDALOpen
+ poDS->nRasterXSize = poDS->sCellInfo.cols;
+ poDS->nRasterYSize = poDS->sCellInfo.rows;
+
+- poDS->adfGeoTransform[0] = poDS->sCellInfo.west;
+- poDS->adfGeoTransform[1] = poDS->sCellInfo.ew_res;
+- poDS->adfGeoTransform[2] = 0.0;
+- poDS->adfGeoTransform[3] = poDS->sCellInfo.north;
+- poDS->adfGeoTransform[4] = 0.0;
+- poDS->adfGeoTransform[5] = -1 * poDS->sCellInfo.ns_res;
++ poDS->m_gt[0] = poDS->sCellInfo.west;
++ poDS->m_gt[1] = poDS->sCellInfo.ew_res;
++ poDS->m_gt[2] = 0.0;
++ poDS->m_gt[3] = poDS->sCellInfo.north;
++ poDS->m_gt[4] = 0.0;
++ poDS->m_gt[5] = -1 * poDS->sCellInfo.ns_res;
+
+ /* -------------------------------------------------------------------- */
+ /* Try to get a projection definition. */
+ /* -------------------------------------------------------------------- */
+- struct Key_Value *projinfo, *projunits;
++ struct Key_Value *projinfo = G_get_projinfo();
++ struct Key_Value *projunits = G_get_projunits();
+
+- projinfo = G_get_projinfo();
+- projunits = G_get_projunits();
+ char *pszWKT = GPJ_grass_to_wkt(projinfo, projunits, 0, 0);
+ if (projinfo)
+ G_free_key_value(projinfo);
+@@ -1080,10 +1024,11 @@ GDALDataset *GRASSDataset::Open(GDALOpen
+ /* -------------------------------------------------------------------- */
+ /* Create band information objects. */
+ /* -------------------------------------------------------------------- */
+- for (int iBand = 0; papszCells[iBand] != NULL; iBand++)
++ for (int iBand = 0; papszCells[iBand] != nullptr; iBand++)
+ {
+- GRASSRasterBand *rb = new GRASSRasterBand(
+- poDS, iBand + 1, papszMapsets[iBand], papszCells[iBand]);
++ std::string msets = std::string(papszMapsets[iBand]);
++ std::string cells = std::string(papszCells[iBand]);
++ auto rb = new GRASSRasterBand(poDS, iBand + 1, msets, cells);
+
+ if (!rb->valid)
+ {
+@@ -1091,7 +1036,7 @@ GDALDataset *GRASSDataset::Open(GDALOpen
+ "GRASS: Cannot open raster band %d", iBand);
+ delete rb;
+ delete poDS;
+- return NULL;
++ return nullptr;
+ }
+
+ poDS->SetBand(iBand + 1, rb);
+@@ -1109,13 +1054,68 @@ GDALDataset *GRASSDataset::Open(GDALOpen
+ CPLError(CE_Failure, CPLE_NotSupported,
+ "The GRASS driver does not support update access to existing"
+ " datasets.\n");
+- return NULL;
++ return nullptr;
+ }
+
+ return poDS;
+ }
+
+ /************************************************************************/
++/* GRASSRasterPath */
++/************************************************************************/
++
++GRASSRasterPath::GRASSRasterPath(const char *path)
++{
++ if (!path || std::strlen(path) == 0)
++ return;
++
++ char *p = nullptr;
++ std::array<char *, 5> ptr{};
++ int i = 0;
++ auto tmp = std::unique_ptr<char[]>(new char[std::strlen(path) + 1]);
++
++ std::strcpy(tmp.get(), path);
++
++ while ((p = std::strrchr(tmp.get(), '/')) != nullptr && i < 4)
++ {
++ *p = '\0';
++
++ if (std::strlen(p + 1) == 0) /* repeated '/' */
++ continue;
++
++ ptr[i++] = p + 1;
++ }
++
++ /* Note: empty GISDBASE == 0 is not accepted (relative path) */
++ if (i != 4)
++ {
++ return;
++ }
++
++ gisdbase = std::string(tmp.get());
++ location = std::string(ptr[3]);
++ mapset = std::string(ptr[2]);
++ element = std::string(ptr[1]);
++ name = std::string(ptr[0]);
++
++ return;
++}
++
++auto GRASSRasterPath::isValid() -> bool
++{
++ if (name.empty() || (element != "cellhd" && element != "group"))
++ {
++ return false;
++ }
++ return true;
++}
++
++auto GRASSRasterPath::isCellHD() -> bool
++{
++ return element == "cellhd";
++}
++
++/************************************************************************/
+ /* GDALRegister_GRASS() */
+ /************************************************************************/
+
+@@ -1124,10 +1124,10 @@ void GDALRegister_GRASS()
+ if (!GDAL_CHECK_VERSION("GDAL/GRASS driver"))
+ return;
+
+- if (GDALGetDriverByName("GRASS") != NULL)
++ if (GDALGetDriverByName("GRASS") != nullptr)
+ return;
+
+- GDALDriver *poDriver = new GDALDriver();
++ auto poDriver = new GDALDriver();
+
+ poDriver->SetDescription("GRASS");
+ poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
+--- a/ogrgrass.h
++++ b/ogrgrass.h
+@@ -1,5 +1,4 @@
+ /******************************************************************************
+- * $Id$
+ *
+ * Project: OpenGIS Simple Features Reference Implementation
+ * Purpose: Private definitions for OGR/GRASS driver.
+@@ -8,23 +7,8 @@
+ ******************************************************************************
+ * Copyright (c) 2005, Radim Blazek <radim.blazek at gmail.com>
+ *
+- * Permission is hereby granted, free of charge, to any person obtaining a
+- * copy of this software and associated documentation files (the "Software"),
+- * to deal in the Software without restriction, including without limitation
+- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+- * and/or sell copies of the Software, and to permit persons to whom the
+- * Software is furnished to do so, subject to the following conditions:
++ * SPDX-License-Identifier: MIT
+ *
+- * The above copyright notice and this permission notice shall be included
+- * in all copies or substantial portions of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+- * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+ #ifndef OGRGRASS_H_INCLUDED
+@@ -52,35 +36,54 @@ class OGRGRASSLayer final : public OGRLa
+ virtual ~OGRGRASSLayer();
+
+ // Layer info
+- OGRFeatureDefn *GetLayerDefn() override
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
++ auto GetName() const -> const char * override
++#else
++ auto GetName() -> const char * override
++#endif
++ {
++ return osName.c_str();
++ }
++
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
++ auto GetLayerDefn() const -> const OGRFeatureDefn * override
++#else
++ auto GetLayerDefn() -> OGRFeatureDefn * override
++#endif
+ {
+ return poFeatureDefn;
+ }
+- GIntBig GetFeatureCount(int) override;
++ auto GetFeatureCount(int) -> GIntBig override;
+
+ #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 11, 0)
+- OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
+- override;
++ auto IGetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
++ -> OGRErr override;
+ #else
+- OGRErr GetExtent(OGREnvelope *psExtent, int bForce) override;
+- virtual OGRErr GetExtent(int iGeomField, OGREnvelope *psExtent,
+- int bForce) override
++ auto GetExtent(OGREnvelope *psExtent, int bForce) -> OGRErr override;
++ virtual auto GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce)
++ -> OGRErr override
+ {
+ return OGRLayer::GetExtent(iGeomField, psExtent, bForce);
+ }
+ #endif
+
+- virtual OGRSpatialReference *GetSpatialRef() override;
+- int TestCapability(const char *) override;
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
++ auto GetSpatialRef() const -> const OGRSpatialReference * override;
++ auto TestCapability(const char *) const -> int override;
++#else
++ auto GetSpatialRef() -> OGRSpatialReference * override;
++ auto TestCapability(const char *) -> int override;
++#endif
+
+ // Reading
+ void ResetReading() override;
+- virtual OGRErr SetNextByIndex(GIntBig nIndex) override;
+- OGRFeature *GetNextFeature() override;
+- OGRFeature *GetFeature(GIntBig nFeatureId) override;
++ virtual auto SetNextByIndex(GIntBig nIndex) -> OGRErr override;
++ auto GetNextFeature() -> OGRFeature * override;
++ auto GetFeature(GIntBig nFeatureId) -> OGRFeature * override;
+
+ // Filters
+- virtual OGRErr SetAttributeFilter(const char *query) override;
++ virtual auto SetAttributeFilter(const char *query) -> OGRErr override;
++
+ #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 11, 0)
+ virtual OGRErr ISetSpatialFilter(int iGeomField,
+ const OGRGeometry *poGeom) override;
+@@ -93,12 +96,12 @@ class OGRGRASSLayer final : public OGRLa
+ #endif
+
+ private:
+- char *pszName;
++ std::string osName;
+ OGRSpatialReference *poSRS;
+ OGRFeatureDefn *poFeatureDefn;
+ char *pszQuery; // Attribute filter string
+
+- int iNextId;
++ GIntBig iNextId;
+ int nTotalCount;
+ int iLayer; // Layer number
+ int iLayerIndex; // Layer index (in GRASS category index)
+@@ -123,21 +126,21 @@ class OGRGRASSLayer final : public OGRLa
+ struct line_pnts *poPoints;
+ struct line_cats *poCats;
+
+- bool StartDbDriver();
+- bool StopDbDriver();
++ auto StartDbDriver() -> bool;
++ auto StopDbDriver() -> bool;
+
+- OGRGeometry *GetFeatureGeometry(long nFeatureId, int *cat);
+- bool SetAttributes(OGRFeature *feature, dbTable *table);
++ auto GetFeatureGeometry(long nFeatureId, int *cat) -> OGRGeometry *;
++ auto SetAttributes(OGRFeature *feature, dbTable *table) -> bool;
+
+ // Features matching spatial filter for ALL features/elements in GRASS
+ char *paSpatialMatch;
+- bool SetSpatialMatch();
++ auto SetSpatialMatch() -> bool;
+
+ // Features matching attribute filter for ALL features/elements in GRASS
+ char *paQueryMatch;
+- bool OpenSequentialCursor();
+- bool ResetSequentialCursor();
+- bool SetQueryMatch();
++ auto OpenSequentialCursor() -> bool;
++ auto ResetSequentialCursor() -> bool;
++ auto SetQueryMatch() -> bool;
+ };
+
+ /************************************************************************/
+@@ -146,38 +149,50 @@ class OGRGRASSLayer final : public OGRLa
+ class OGRGRASSDataSource final : public OGRDataSource
+ {
+ public:
+- OGRGRASSDataSource();
++ OGRGRASSDataSource() = default;
+ virtual ~OGRGRASSDataSource();
+
+- bool Open(const char *, bool bUpdate, bool bTestOpen,
+- bool bSingleNewFile = false);
++ auto Open(const char *, bool bUpdate, bool bTestOpen,
++ bool bSingleNewFile = false) -> bool;
+
+- const char *GetName() override
++ auto GetName() -> const char * override
+ {
+- return pszName;
++ return osName.c_str();
+ }
+- int GetLayerCount() override
++
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
++ auto GetLayerCount() const -> int override
++#else
++ auto GetLayerCount() -> int override
++#endif
+ {
+ return nLayers;
+ }
+- OGRLayer *GetLayer(int) override;
+
+- int TestCapability(const char *) override;
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
++ auto GetLayer(int) const -> const OGRLayer * override;
++ auto TestCapability(const char *) const -> int override;
++#else
++ auto GetLayer(int) -> OGRLayer * override;
++ auto TestCapability(const char *) -> int override;
++#endif
+
+ private:
+- OGRGRASSLayer **papoLayers;
+- char *pszName; // Date source name
+- char *pszGisdbase; // GISBASE
+- char *pszLocation; // location name
+- char *pszMapset; // mapset name
+- char *pszMap; // name of vector map
++ OGRGRASSLayer **papoLayers{nullptr};
++ std::string osName; // Date source name
++ std::string osGisdbase; // GISBASE
++ std::string osLocation; // location name
++ std::string osMapset; // mapset name
++ std::string osMap; // name of vector map
+
+- struct Map_info map;
+- int nLayers;
++ struct Map_info map
++ {
++ };
++ int nLayers{0};
+
+- bool bOpened;
++ bool bOpened{false};
+
+- static bool SplitPath(char *, char **, char **, char **, char **);
++ auto SetPath(const char *) -> bool;
+ };
+
+ #endif /* ndef OGRGRASS_H_INCLUDED */
+--- a/ogrgrassdatasource.cpp
++++ b/ogrgrassdatasource.cpp
+@@ -8,25 +8,13 @@
+ * Copyright (c) 2005, Radim Blazek <radim.blazek at gmail.com>
+ * Copyright (c) 2008-2020, Even Rouault <even dot rouault at spatialys.com>
+ *
+- * Permission is hereby granted, free of charge, to any person obtaining a
+- * copy of this software and associated documentation files (the "Software"),
+- * to deal in the Software without restriction, including without limitation
+- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+- * and/or sell copies of the Software, and to permit persons to whom the
+- * Software is furnished to do so, subject to the following conditions:
++ * SPDX-License-Identifier: MIT
+ *
+- * The above copyright notice and this permission notice shall be included
+- * in all copies or substantial portions of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+- * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
++#include <array>
++#include <cstring>
++
+ #include "ogrgrass.h"
+ #include "cpl_conv.h"
+ #include "cpl_string.h"
+@@ -34,7 +22,7 @@
+ /************************************************************************/
+ /* Grass2CPLErrorHook() */
+ /************************************************************************/
+-static int Grass2OGRErrorHook(char *pszMessage, int bFatal)
++static auto Grass2CPLErrorHook(char *pszMessage, int bFatal) -> int
+ {
+ if (!bFatal)
+ CPLError(CE_Warning, CPLE_AppDefined, "GRASS warning: %s", pszMessage);
+@@ -46,21 +34,6 @@ static int Grass2OGRErrorHook(char *pszM
+ }
+
+ /************************************************************************/
+-/* OGRGRASSDataSource() */
+-/************************************************************************/
+-OGRGRASSDataSource::OGRGRASSDataSource()
+-{
+- pszName = NULL;
+- pszGisdbase = NULL;
+- pszLocation = NULL;
+- pszMapset = NULL;
+- pszMap = NULL;
+- papoLayers = NULL;
+- nLayers = 0;
+- bOpened = FALSE;
+-}
+-
+-/************************************************************************/
+ /* ~OGRGRASSDataSource() */
+ /************************************************************************/
+ OGRGRASSDataSource::~OGRGRASSDataSource()
+@@ -68,19 +41,6 @@ OGRGRASSDataSource::~OGRGRASSDataSource(
+ for (int i = 0; i < nLayers; i++)
+ delete papoLayers[i];
+
+- if (pszName)
+- CPLFree(pszName);
+- if (papoLayers)
+- CPLFree(papoLayers);
+- if (pszGisdbase)
+- G_free(pszGisdbase);
+- if (pszLocation)
+- G_free(pszLocation);
+- if (pszMapset)
+- G_free(pszMapset);
+- if (pszMap)
+- G_free(pszMap);
+-
+ if (bOpened)
+ Vect_close(&map);
+ }
+@@ -89,27 +49,25 @@ OGRGRASSDataSource::~OGRGRASSDataSource(
+ /* Open() */
+ /************************************************************************/
+
+-typedef int (*GrassErrorHandler)(const char *, int);
++using GrassErrorHandler = auto(*)(const char *, int) -> int;
+
+-bool OGRGRASSDataSource::Open(const char *pszNewName, bool /*bUpdate*/,
+- bool bTestOpen, bool /*bSingleNewFileIn*/)
++auto OGRGRASSDataSource::Open(const char *pszNewName, bool /*bUpdate*/,
++ bool bTestOpen, bool /*bSingleNewFileIn*/) -> bool
+ {
+ VSIStatBuf stat;
+
+ CPLAssert(nLayers == 0);
+
+- pszName = CPLStrdup(pszNewName); // Released by destructor
+-
+ /* -------------------------------------------------------------------- */
+ /* Do the given path contains 'vector' and 'head'? */
+ /* -------------------------------------------------------------------- */
+- if (strstr(pszName, "vector") == nullptr ||
+- strstr(pszName, "head") == nullptr)
++ if (std::strstr(pszNewName, "vector") == nullptr ||
++ std::strstr(pszNewName, "head") == nullptr)
+ {
+ if (!bTestOpen)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+- "%s is not GRASS vector, access failed.\n", pszName);
++ "%s is not GRASS vector, access failed.\n", pszNewName);
+ }
+ return false;
+ }
+@@ -117,12 +75,12 @@ bool OGRGRASSDataSource::Open(const char
+ /* -------------------------------------------------------------------- */
+ /* Is the given a regular file? */
+ /* -------------------------------------------------------------------- */
+- if (CPLStat(pszName, &stat) != 0 || !VSI_ISREG(stat.st_mode))
++ if (CPLStat(pszNewName, &stat) != 0 || !VSI_ISREG(stat.st_mode))
+ {
+ if (!bTestOpen)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+- "%s is not GRASS vector, access failed.\n", pszName);
++ "%s is not GRASS vector, access failed.\n", pszNewName);
+ }
+
+ return false;
+@@ -131,21 +89,21 @@ bool OGRGRASSDataSource::Open(const char
+ /* -------------------------------------------------------------------- */
+ /* Parse datasource name */
+ /* -------------------------------------------------------------------- */
+- if (!SplitPath(pszName, &pszGisdbase, &pszLocation, &pszMapset, &pszMap))
++ if (!SetPath(pszNewName))
+ {
+ if (!bTestOpen)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "%s is not GRASS datasource name, access failed.\n",
+- pszName);
++ pszNewName);
+ }
+ return false;
+ }
+
+- CPLDebug("GRASS", "Gisdbase: %s", pszGisdbase);
+- CPLDebug("GRASS", "Location: %s", pszLocation);
+- CPLDebug("GRASS", "Mapset: %s", pszMapset);
+- CPLDebug("GRASS", "Map: %s", pszMap);
++ CPLDebug("GRASS", "Gisdbase: %s", osGisdbase.c_str());
++ CPLDebug("GRASS", "Location: %s", osLocation.c_str());
++ CPLDebug("GRASS", "Mapset: %s", osMapset.c_str());
++ CPLDebug("GRASS", "Map: %s", osMap.c_str());
+
+ /* -------------------------------------------------------------------- */
+ /* Init GRASS library */
+@@ -160,12 +118,11 @@ bool OGRGRASSDataSource::Open(const char
+ "GRASS warning: GISBASE "
+ "environment variable was not set, using:\n%s",
+ gisbase);
+- char buf[2000];
+- snprintf(buf, sizeof(buf), "GISBASE=%s", gisbase);
+- buf[sizeof(buf) - 1] = '\0';
++ std::array<char, 2000> buf{};
++ (void)snprintf(buf.data(), buf.size(), "GISBASE=%s", gisbase);
+
+ CPLFree(gisbaseEnv);
+- gisbaseEnv = CPLStrdup(buf);
++ gisbaseEnv = CPLStrdup(buf.data());
+ putenv(gisbaseEnv);
+ }
+
+@@ -178,27 +135,27 @@ bool OGRGRASSDataSource::Open(const char
+ G_no_gisinit();
+
+ // Set error function
+- G_set_error_routine((GrassErrorHandler)Grass2OGRErrorHook);
++ G_set_error_routine(GrassErrorHandler(Grass2CPLErrorHook));
+
+ /* -------------------------------------------------------------------- */
+ /* Set GRASS variables */
+ /* -------------------------------------------------------------------- */
+- G_setenv_nogisrc("GISDBASE", pszGisdbase);
+- G_setenv_nogisrc("LOCATION_NAME", pszLocation);
+- G_setenv_nogisrc("MAPSET", pszMapset);
++ G_setenv_nogisrc("GISDBASE", osGisdbase.c_str());
++ G_setenv_nogisrc("LOCATION_NAME", osLocation.c_str());
++ G_setenv_nogisrc("MAPSET", osMapset.c_str());
+ G_reset_mapsets();
+- G_add_mapset_to_search_path(pszMapset);
++ G_add_mapset_to_search_path(osMapset.c_str());
+
+ /* -------------------------------------------------------------------- */
+ /* Open GRASS vector map */
+ /* -------------------------------------------------------------------- */
+ Vect_set_open_level(2);
+- int level = Vect_open_old(&map, pszMap, pszMapset);
++ int level = Vect_open_old(&map, osMap.c_str(), osMapset.c_str());
+
+ if (level < 2)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+- "Cannot open GRASS vector %s on level 2.\n", pszName);
++ "Cannot open GRASS vector %s on level 2.\n", osName.c_str());
+ return false;
+ }
+
+@@ -213,11 +170,11 @@ bool OGRGRASSDataSource::Open(const char
+ for (int i = 0; i < ncidx; i++)
+ {
+ // Create the layer object
+- OGRGRASSLayer *poLayer = new OGRGRASSLayer(i, &map);
++ auto poLayer = new OGRGRASSLayer(i, &map);
+
+ // Add layer to data source layer list
+- papoLayers = (OGRGRASSLayer **)CPLRealloc(
+- papoLayers, sizeof(OGRGRASSLayer *) * (nLayers + 1));
++ papoLayers = reinterpret_cast<OGRGRASSLayer **>(
++ CPLRealloc(papoLayers, sizeof(OGRGRASSLayer *) * (nLayers + 1)));
+ papoLayers[nLayers++] = poLayer;
+ }
+
+@@ -229,7 +186,11 @@ bool OGRGRASSDataSource::Open(const char
+ /************************************************************************/
+ /* TestCapability() */
+ /************************************************************************/
+-int OGRGRASSDataSource::TestCapability(const char * /* pszCap*/)
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
++auto OGRGRASSDataSource::TestCapability(const char * /* pszCap*/) const -> int
++#else
++auto OGRGRASSDataSource::TestCapability(const char * /* pszCap*/) -> int
++#endif
+ {
+ return FALSE;
+ }
+@@ -237,10 +198,14 @@ int OGRGRASSDataSource::TestCapability(c
+ /************************************************************************/
+ /* GetLayer() */
+ /************************************************************************/
+-OGRLayer *OGRGRASSDataSource::GetLayer(int iLayer)
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
++auto OGRGRASSDataSource::GetLayer(int iLayer) const -> const OGRLayer *
++#else
++auto OGRGRASSDataSource::GetLayer(int iLayer) -> OGRLayer *
++#endif
+ {
+ if (iLayer < 0 || iLayer >= nLayers)
+- return NULL;
++ return nullptr;
+ else
+ return papoLayers[iLayer];
+ }
+@@ -254,26 +219,25 @@ OGRLayer *OGRGRASSDataSource::GetLayer(i
+ /* Returns: true - OK */
+ /* false - failed */
+ /************************************************************************/
+-bool OGRGRASSDataSource::SplitPath(char *path, char **gisdbase, char **location,
+- char **mapset, char **map)
++auto OGRGRASSDataSource::SetPath(const char *path) -> bool
+ {
+- char *p, *ptr[5], *tmp;
+- int i = 0;
+-
+- CPLDebug("GRASS", "OGRGRASSDataSource::SplitPath");
++ CPLDebug("GRASS", "OGRGRASSDataSource::SetPath");
+
+- *gisdbase = *location = *mapset = *map = NULL;
+-
+- if (!path || strlen(path) == 0)
++ if (!path || std::strlen(path) == 0)
+ return false;
+
+- tmp = G_store(path);
++ char *p = nullptr;
++ std::array<char *, 6> ptr{};
++ int i = 0;
++ auto tmp = std::unique_ptr<char[]>(new char[std::strlen(path) + 1]);
++
++ std::strcpy(tmp.get(), path);
+
+- while ((p = strrchr(tmp, '/')) != NULL && i < 5)
++ while ((p = std::strrchr(tmp.get(), '/')) != nullptr && i < 5)
+ {
+ *p = '\0';
+
+- if (strlen(p + 1) == 0) /* repeated '/' */
++ if (std::strlen(p + 1) == 0) /* repeated '/' */
+ continue;
+
+ ptr[i++] = p + 1;
+@@ -282,20 +246,19 @@ bool OGRGRASSDataSource::SplitPath(char
+ /* Note: empty GISDBASE == 0 is not accepted (relative path) */
+ if (i != 5)
+ {
+- free(tmp);
+ return false;
+ }
+
+- if (strcmp(ptr[0], "head") != 0 || strcmp(ptr[2], "vector") != 0)
++ if (std::strcmp(ptr[0], "head") != 0 || std::strcmp(ptr[2], "vector") != 0)
+ {
+ return false;
+ }
+
+- *gisdbase = G_store(tmp);
+- *location = G_store(ptr[4]);
+- *mapset = G_store(ptr[3]);
+- *map = G_store(ptr[1]);
++ osName = std::string(path);
++ osGisdbase = std::string(tmp.get());
++ osLocation = std::string(ptr[4]);
++ osMapset = std::string(ptr[3]);
++ osMap = std::string(ptr[1]);
+
+- free(tmp);
+ return true;
+ }
+--- a/ogrgrasslayer.cpp
++++ b/ogrgrasslayer.cpp
+@@ -8,26 +8,13 @@
+ * Copyright (c) 2005, Radim Blazek <radim.blazek at gmail.com>
+ * Copyright (c) 2008-2020, Even Rouault <even dot rouault at spatialys.com>
+ *
+- * Permission is hereby granted, free of charge, to any person obtaining a
+- * copy of this software and associated documentation files (the "Software"),
+- * to deal in the Software without restriction, including without limitation
+- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+- * and/or sell copies of the Software, and to permit persons to whom the
+- * Software is furnished to do so, subject to the following conditions:
++ * SPDX-License-Identifier: MIT
+ *
+- * The above copyright notice and this permission notice shall be included
+- * in all copies or substantial portions of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+- * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+-#include <signal.h>
++#include <array>
++#include <csignal>
++
+ #include "ogrgrass.h"
+ #include "cpl_conv.h"
+
+@@ -35,36 +22,28 @@
+ /* OGRGRASSLayer() */
+ /************************************************************************/
+ OGRGRASSLayer::OGRGRASSLayer(int layerIndex, struct Map_info *map)
++ : poSRS(nullptr), pszQuery(nullptr), iNextId(0),
++ iLayer(Vect_cidx_get_field_number(map, layerIndex)),
++ iLayerIndex(layerIndex), poMap(map),
++ poLink(Vect_get_field(poMap, iLayer)), iCurrentCat(0),
++ poPoints(Vect_new_line_struct()), poCats(Vect_new_cats_struct()),
++ paSpatialMatch(nullptr), paQueryMatch(nullptr)
+ {
+ CPLDebug("GRASS", "OGRGRASSLayer::OGRGRASSLayer layerIndex = %d",
+ layerIndex);
+
+- iLayerIndex = layerIndex;
+- poMap = map;
+- poSRS = NULL;
+- iNextId = 0;
+- poPoints = Vect_new_line_struct();
+- poCats = Vect_new_cats_struct();
+- pszQuery = NULL;
+- paQueryMatch = NULL;
+- paSpatialMatch = NULL;
+- iCurrentCat = 0;
+-
+- iLayer = Vect_cidx_get_field_number(poMap, iLayerIndex);
+ CPLDebug("GRASS", "iLayer = %d", iLayer);
+
+- poLink = Vect_get_field(poMap, iLayer); // May be NULL if not defined
++ // poLink may be NULL if not defined
+
+ // Layer name
+ if (poLink && poLink->name)
+ {
+- pszName = CPLStrdup(poLink->name);
++ osName = std::string(poLink->name);
+ }
+ else
+ {
+- char buf[20];
+- snprintf(buf, sizeof(buf), "%d", iLayer);
+- pszName = CPLStrdup(buf);
++ osName = std::to_string(iLayer);
+ }
+
+ // Because we don't represent centroids as any simple feature, we have to scan
+@@ -72,14 +51,14 @@ OGRGRASSLayer::OGRGRASSLayer(int layerIn
+ nTotalCount =
+ Vect_cidx_get_type_count(poMap, iLayer, GV_POINT | GV_LINES | GV_AREA);
+ CPLDebug("GRASS", "nTotalCount = %d", nTotalCount);
+- paFeatureIndex = (int *)CPLMalloc(nTotalCount * sizeof(int));
++ paFeatureIndex = static_cast<int *>(CPLMalloc(nTotalCount * sizeof(int)));
+
+ int n =
+ Vect_cidx_get_type_count(poMap, iLayer, GV_POINTS | GV_LINES | GV_AREA);
+ int cnt = 0;
+ for (int i = 0; i < n; i++)
+ {
+- int cat, type, id;
++ int cat = 0, type = 0, id = 0;
+
+ Vect_cidx_get_cat_by_index(poMap, iLayerIndex, i, &cat, &type, &id);
+
+@@ -88,7 +67,7 @@ OGRGRASSLayer::OGRGRASSLayer(int layerIn
+ paFeatureIndex[cnt++] = i;
+ }
+
+- poFeatureDefn = new OGRFeatureDefn(pszName);
++ poFeatureDefn = new OGRFeatureDefn(osName.c_str());
+ SetDescription(poFeatureDefn->GetName());
+ poFeatureDefn->Reference();
+
+@@ -97,7 +76,7 @@ OGRGRASSLayer::OGRGRASSLayer(int layerIn
+ int types = 0;
+ for (int i = 0; i < nTypes; i++)
+ {
+- int type, count;
++ int type = 0, count = 0;
+ Vect_cidx_get_type_count_by_index(poMap, iLayerIndex, i, &type, &count);
+ if (!(type & (GV_POINT | GV_LINES | GV_AREA)))
+ continue;
+@@ -126,11 +105,11 @@ OGRGRASSLayer::OGRGRASSLayer(int layerIn
+ poFeatureDefn->SetGeomType(eGeomType);
+
+ // Get attributes definition
+- poDbString = (dbString *)CPLMalloc(sizeof(dbString));
+- poCursor = (dbCursor *)CPLMalloc(sizeof(dbCursor));
++ poDbString = reinterpret_cast<dbString *>(CPLMalloc(sizeof(dbString)));
++ poCursor = reinterpret_cast<dbCursor *>(CPLMalloc(sizeof(dbCursor)));
+ bCursorOpened = FALSE;
+
+- poDriver = NULL;
++ poDriver = nullptr;
+ bHaveAttributes = false;
+ db_init_string(poDbString);
+ if (poLink)
+@@ -138,7 +117,7 @@ OGRGRASSLayer::OGRGRASSLayer(int layerIn
+ if (StartDbDriver())
+ {
+ db_set_string(poDbString, poLink->table);
+- dbTable *table = NULL;
++ dbTable *table = nullptr;
+ if (db_describe_table(poDriver, poDbString, &table) == DB_OK)
+ {
+ nFields = db_get_table_number_of_columns(table);
+@@ -187,7 +166,7 @@ OGRGRASSLayer::OGRGRASSLayer(int layerIn
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot find key field");
+ db_close_database_shutdown_driver(poDriver);
+- poDriver = NULL;
++ poDriver = nullptr;
+ }
+ }
+ else
+@@ -196,7 +175,7 @@ OGRGRASSLayer::OGRGRASSLayer(int layerIn
+ "Cannot describe table %s", poLink->table);
+ }
+ db_close_database_shutdown_driver(poDriver);
+- poDriver = NULL;
++ poDriver = nullptr;
+ }
+ }
+
+@@ -209,14 +188,12 @@ OGRGRASSLayer::OGRGRASSLayer(int layerIn
+
+ if (getenv("GISBASE")) // We have some projection info in GISBASE
+ {
+- struct Key_Value *projinfo, *projunits;
+-
+ // Note: we do not have to reset GISDBASE and LOCATION_NAME because
+ // OGRGRASSLayer constructor is called from OGRGRASSDataSource::Open
+ // where those variables are set
+
+- projinfo = G_get_projinfo();
+- projunits = G_get_projunits();
++ struct Key_Value *projinfo = G_get_projinfo();
++ struct Key_Value *projunits = G_get_projunits();
+
+ char *srsWkt = GPJ_grass_to_wkt(projinfo, projunits, 0, 0);
+ if (srsWkt)
+@@ -246,8 +223,6 @@ OGRGRASSLayer::~OGRGRASSLayer()
+ StopDbDriver();
+ }
+
+- if (pszName)
+- CPLFree(pszName);
+ if (poFeatureDefn)
+ poFeatureDefn->Release();
+ if (poSRS)
+@@ -278,7 +253,7 @@ OGRGRASSLayer::~OGRGRASSLayer()
+ /************************************************************************/
+ /* StartDbDriver */
+ /************************************************************************/
+-bool OGRGRASSLayer::StartDbDriver()
++auto OGRGRASSLayer::StartDbDriver() -> bool
+ {
+ CPLDebug("GRASS", "StartDbDriver()");
+
+@@ -290,7 +265,7 @@ bool OGRGRASSLayer::StartDbDriver()
+ }
+ poDriver = db_start_driver_open_database(poLink->driver, poLink->database);
+
+- if (poDriver == NULL)
++ if (poDriver == nullptr)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot open database %s by driver %s, "
+@@ -306,7 +281,7 @@ bool OGRGRASSLayer::StartDbDriver()
+ /************************************************************************/
+ /* StopDbDriver */
+ /************************************************************************/
+-bool OGRGRASSLayer::StopDbDriver()
++auto OGRGRASSLayer::StopDbDriver() -> bool
+ {
+ if (!poDriver)
+ {
+@@ -358,9 +333,9 @@ void OGRGRASSLayer::ResetReading()
+ /* If we already have an FID list, we can easily reposition */
+ /* ourselves in it. */
+ /************************************************************************/
+-OGRErr OGRGRASSLayer::SetNextByIndex(GIntBig nIndex)
++auto OGRGRASSLayer::SetNextByIndex(GIntBig nIndex) -> OGRErr
+ {
+- if (m_poFilterGeom != NULL || m_poAttrQuery != NULL)
++ if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr)
+ {
+ iNextId = 0;
+ int count = 0;
+@@ -373,7 +348,7 @@ OGRErr OGRGRASSLayer::SetNextByIndex(GIn
+ break;
+
+ // Attributes
+- if (pszQuery != NULL && !paQueryMatch[iNextId])
++ if (pszQuery != nullptr && !paQueryMatch[iNextId])
+ {
+ iNextId++;
+ continue;
+@@ -389,7 +364,7 @@ OGRErr OGRGRASSLayer::SetNextByIndex(GIn
+ }
+ }
+
+- iNextId = nIndex;
++ iNextId = (int)nIndex;
+
+ return OGRERR_NONE;
+ }
+@@ -397,27 +372,27 @@ OGRErr OGRGRASSLayer::SetNextByIndex(GIn
+ /************************************************************************/
+ /* SetAttributeFilter */
+ /************************************************************************/
+-OGRErr OGRGRASSLayer::SetAttributeFilter(const char *query)
++auto OGRGRASSLayer::SetAttributeFilter(const char *query) -> OGRErr
+ {
+ CPLDebug("GRASS", "SetAttributeFilter: %s", query);
+
+- if (query == NULL)
++ if (query == nullptr)
+ {
+ // Release old if any
+ if (pszQuery)
+ {
+ CPLFree(pszQuery);
+- pszQuery = NULL;
++ pszQuery = nullptr;
+ }
+ if (paQueryMatch)
+ {
+ CPLFree(paQueryMatch);
+- paQueryMatch = NULL;
++ paQueryMatch = nullptr;
+ }
+ return OGRERR_NONE;
+ }
+
+- paQueryMatch = (char *)CPLMalloc(nTotalCount);
++ paQueryMatch = reinterpret_cast<char *>(CPLMalloc(nTotalCount));
+ memset(paQueryMatch, 0x0, nTotalCount);
+ pszQuery = CPLStrdup(query);
+
+@@ -448,16 +423,16 @@ OGRErr OGRGRASSLayer::SetAttributeFilter
+ else
+ {
+ CPLFree(pszQuery);
+- pszQuery = NULL;
++ pszQuery = nullptr;
+ return OGRERR_FAILURE;
+ }
+ db_close_database_shutdown_driver(poDriver);
+- poDriver = NULL;
++ poDriver = nullptr;
+ }
+ else
+ {
+ CPLFree(pszQuery);
+- pszQuery = NULL;
++ pszQuery = nullptr;
+ return OGRERR_FAILURE;
+ }
+ }
+@@ -482,7 +457,7 @@ OGRErr OGRGRASSLayer::SetAttributeFilter
+ /************************************************************************/
+ /* SetQueryMatch */
+ /************************************************************************/
+-bool OGRGRASSLayer::SetQueryMatch()
++auto OGRGRASSLayer::SetQueryMatch() -> bool
+ {
+ CPLDebug("GRASS", "SetQueryMatch");
+
+@@ -495,7 +470,7 @@ bool OGRGRASSLayer::SetQueryMatch()
+ return false;
+ }
+
+- int more;
++ int more = 0;
+ int cidx = 0; // index to category index
+ int fidx = 0; // index to feature index (paFeatureIndex)
+ // number of categories in category index
+@@ -573,7 +548,7 @@ bool OGRGRASSLayer::SetQueryMatch()
+ /************************************************************************/
+ /* OpenSequentialCursor */
+ /************************************************************************/
+-bool OGRGRASSLayer::OpenSequentialCursor()
++auto OGRGRASSLayer::OpenSequentialCursor() -> bool
+ {
+ CPLDebug("GRASS", "OpenSequentialCursor: %s", pszQuery);
+
+@@ -589,18 +564,18 @@ bool OGRGRASSLayer::OpenSequentialCursor
+ bCursorOpened = false;
+ }
+
+- char buf[2000];
+- snprintf(buf, sizeof(buf), "SELECT * FROM %s ", poLink->table);
+- db_set_string(poDbString, buf);
++ std::array<char, 2000> buf{};
++ (void)snprintf(buf.data(), buf.size(), "SELECT * FROM %s ", poLink->table);
++ db_set_string(poDbString, buf.data());
+
+ if (pszQuery)
+ {
+- snprintf(buf, sizeof(buf), "WHERE %s ", pszQuery);
+- db_append_string(poDbString, buf);
++ (void)snprintf(buf.data(), buf.size(), "WHERE %s ", pszQuery);
++ db_append_string(poDbString, buf.data());
+ }
+
+- snprintf(buf, sizeof(buf), "ORDER BY %s", poLink->key);
+- db_append_string(poDbString, buf);
++ (void)snprintf(buf.data(), buf.size(), "ORDER BY %s", poLink->key);
++ db_append_string(poDbString, buf.data());
+
+ CPLDebug("GRASS", "Query: %s", db_get_string(poDbString));
+
+@@ -622,11 +597,11 @@ bool OGRGRASSLayer::OpenSequentialCursor
+ /************************************************************************/
+ /* ResetSequentialCursor */
+ /************************************************************************/
+-bool OGRGRASSLayer::ResetSequentialCursor()
++auto OGRGRASSLayer::ResetSequentialCursor() -> bool
+ {
+ CPLDebug("GRASS", "ResetSequentialCursor");
+
+- int more;
++ int more = 0;
+ if (db_fetch(poCursor, DB_FIRST, &more) != DB_OK)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Cannot reset cursor.");
+@@ -658,19 +633,20 @@ void OGRGRASSLayer::SetSpatialFilter(OGR
+ OGRLayer::SetSpatialFilter(poGeomIn);
+ #endif
+
+- if (poGeomIn == NULL)
++ if (poGeomIn == nullptr)
+ {
+ // Release old if any
+ if (paSpatialMatch)
+ {
+ CPLFree(paSpatialMatch);
+- paSpatialMatch = NULL;
++ paSpatialMatch = nullptr;
+ }
+ }
+ else
+ {
+ SetSpatialMatch();
+ }
++
+ #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 11, 0)
+ return OGRERR_NONE;
+ #endif
+@@ -679,17 +655,17 @@ void OGRGRASSLayer::SetSpatialFilter(OGR
+ /************************************************************************/
+ /* SetSpatialMatch */
+ /************************************************************************/
+-bool OGRGRASSLayer::SetSpatialMatch()
++auto OGRGRASSLayer::SetSpatialMatch() -> bool
+ {
+ CPLDebug("GRASS", "SetSpatialMatch");
+
+ if (!paSpatialMatch)
+ {
+- paSpatialMatch = (char *)CPLMalloc(nTotalCount);
++ paSpatialMatch = static_cast<char *>(CPLMalloc(nTotalCount));
+ }
+ memset(paSpatialMatch, 0x0, nTotalCount);
+
+- OGRLineString *lstring = new OGRLineString();
++ auto lstring = new OGRLineString();
+ lstring->setNumPoints(5);
+ OGRGeometry *geom = lstring;
+
+@@ -697,11 +673,13 @@ bool OGRGRASSLayer::SetSpatialMatch()
+ {
+ int cidx = paFeatureIndex[i];
+
+- int cat, type, id;
++ int cat = 0, type = 0, id = 0;
+
+ Vect_cidx_get_cat_by_index(poMap, iLayerIndex, cidx, &cat, &type, &id);
+
+- struct bound_box box;
++ struct bound_box box
++ {
++ };
+
+ switch (type)
+ {
+@@ -735,12 +713,12 @@ bool OGRGRASSLayer::SetSpatialMatch()
+ /************************************************************************/
+ /* GetNextFeature() */
+ /************************************************************************/
+-OGRFeature *OGRGRASSLayer::GetNextFeature()
++auto OGRGRASSLayer::GetNextFeature() -> OGRFeature *
+ {
+ CPLDebug("GRASS", "OGRGRASSLayer::GetNextFeature");
+- OGRFeature *poFeature = NULL;
++ OGRFeature *poFeature = nullptr;
+
+- int cat;
++ int cat = 0;
+
+ // Get next iNextId
+ while (true)
+@@ -756,14 +734,14 @@ OGRFeature *OGRGRASSLayer::GetNextFeatur
+ if (poDriver)
+ {
+ db_close_database_shutdown_driver(poDriver);
+- poDriver = NULL;
++ poDriver = nullptr;
+ }
+
+- return NULL;
++ return nullptr;
+ }
+
+ // Attributes
+- if (pszQuery != NULL && !paQueryMatch[iNextId])
++ if (pszQuery != nullptr && !paQueryMatch[iNextId])
+ {
+ iNextId++;
+ continue;
+@@ -807,7 +785,7 @@ OGRFeature *OGRGRASSLayer::GetNextFeatur
+ {
+ while (true)
+ {
+- int more;
++ int more = 0;
+ if (db_fetch(poCursor, DB_NEXT, &more) != DB_OK)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+@@ -849,16 +827,16 @@ OGRFeature *OGRGRASSLayer::GetNextFeatur
+ /************************************************************************/
+ /* GetFeature() */
+ /************************************************************************/
+-OGRFeature *OGRGRASSLayer::GetFeature(GIntBig nFeatureId)
++auto OGRGRASSLayer::GetFeature(GIntBig nFeatureId) -> OGRFeature *
+
+ {
+ CPLDebug("GRASS", "OGRGRASSLayer::GetFeature nFeatureId = " CPL_FRMT_GIB,
+ nFeatureId);
+
+- int cat;
++ int cat = 0;
+ OGRGeometry *poOGR = GetFeatureGeometry(nFeatureId, &cat);
+
+- OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
++ auto poFeature = new OGRFeature(poFeatureDefn);
+ poFeature->SetGeometryDirectly(poOGR);
+ poFeature->SetFID(nFeatureId);
+
+@@ -875,10 +853,10 @@ OGRFeature *OGRGRASSLayer::GetFeature(GI
+ bCursorOpened = false;
+ }
+ CPLDebug("GRASS", "Open cursor for key = %d", cat);
+- char buf[2000];
+- snprintf(buf, sizeof(buf), "SELECT * FROM %s WHERE %s = %d",
+- poLink->table, poLink->key, cat);
+- db_set_string(poDbString, buf);
++ std::array<char, 2000> buf{};
++ (void)snprintf(buf.data(), buf.size(), "SELECT * FROM %s WHERE %s = %d",
++ poLink->table, poLink->key, cat);
++ db_set_string(poDbString, buf.data());
+ if (db_open_select_cursor(poDriver, poDbString, poCursor,
+ DB_SEQUENTIAL) == DB_OK)
+ {
+@@ -892,7 +870,7 @@ OGRFeature *OGRGRASSLayer::GetFeature(GI
+
+ if (bCursorOpened)
+ {
+- int more;
++ int more = 0;
+ if (db_fetch(poCursor, DB_NEXT, &more) != DB_OK)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+@@ -927,19 +905,20 @@ OGRFeature *OGRGRASSLayer::GetFeature(GI
+ /************************************************************************/
+ /* GetFeatureGeometry() */
+ /************************************************************************/
+-OGRGeometry *OGRGRASSLayer::GetFeatureGeometry(long nFeatureId, int *cat)
++auto OGRGRASSLayer::GetFeatureGeometry(long nFeatureId, int *cat)
++ -> OGRGeometry *
+ {
+ CPLDebug("GRASS", "OGRGRASSLayer::GetFeatureGeometry nFeatureId = %ld",
+ nFeatureId);
+
+ int cidx = paFeatureIndex[(int)nFeatureId];
+
+- int type, id;
++ int type = 0, id = 0;
+ Vect_cidx_get_cat_by_index(poMap, iLayerIndex, cidx, cat, &type, &id);
+
+ //CPLDebug ( "GRASS", "cat = %d type = %d id = %d", *cat, type, id );
+
+- OGRGeometry *poOGR = NULL;
++ OGRGeometry *poOGR = nullptr;
+ int bIs3D = Vect_is_3d(poMap);
+
+ switch (type)
+@@ -959,7 +938,7 @@ OGRGeometry *OGRGRASSLayer::GetFeatureGe
+ case GV_BOUNDARY:
+ {
+ Vect_read_line(poMap, poPoints, poCats, id);
+- OGRLineString *poOGRLine = new OGRLineString();
++ auto poOGRLine = new OGRLineString();
+ if (bIs3D)
+ poOGRLine->setPoints(poPoints->n_points, poPoints->x,
+ poPoints->y, poPoints->z);
+@@ -975,9 +954,9 @@ OGRGeometry *OGRGRASSLayer::GetFeatureGe
+ {
+ Vect_get_area_points(poMap, id, poPoints);
+
+- OGRPolygon *poOGRPoly = new OGRPolygon();
++ auto poOGRPoly = new OGRPolygon();
+
+- OGRLinearRing *poRing = new OGRLinearRing();
++ auto poRing = new OGRLinearRing();
+ if (bIs3D)
+ poRing->setPoints(poPoints->n_points, poPoints->x, poPoints->y,
+ poPoints->z);
+@@ -1012,7 +991,7 @@ OGRGeometry *OGRGRASSLayer::GetFeatureGe
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Unknown GRASS feature type.");
+- return NULL;
++ return nullptr;
+ }
+ }
+
+@@ -1022,7 +1001,7 @@ OGRGeometry *OGRGRASSLayer::GetFeatureGe
+ /************************************************************************/
+ /* SetAttributes() */
+ /************************************************************************/
+-bool OGRGRASSLayer::SetAttributes(OGRFeature *poFeature, dbTable *table)
++auto OGRGRASSLayer::SetAttributes(OGRFeature *poFeature, dbTable *table) -> bool
+ {
+ CPLDebug("GRASS", "OGRGRASSLayer::SetAttributes");
+
+@@ -1067,9 +1046,9 @@ bool OGRGRASSLayer::SetAttributes(OGRFea
+ /* Eventually we should consider implementing a more efficient */
+ /* way of counting features matching a spatial query. */
+ /************************************************************************/
+-GIntBig OGRGRASSLayer::GetFeatureCount(int bForce)
++auto OGRGRASSLayer::GetFeatureCount(int bForce) -> GIntBig
+ {
+- if (m_poFilterGeom != NULL || m_poAttrQuery != NULL)
++ if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr)
+ return OGRLayer::GetFeatureCount(bForce);
+
+ return nTotalCount;
+@@ -1084,14 +1063,17 @@ GIntBig OGRGRASSLayer::GetFeatureCount(i
+ /* */
+ /* Returns OGRERR_NONE/OGRRERR_FAILURE. */
+ /************************************************************************/
++
+ #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 11, 0)
+-OGRErr OGRGRASSLayer::IGetExtent(int /*iGeomField */, OGREnvelope *psExtent,
+- bool /*bForce*/)
++auto OGRGRASSLayer::IGetExtent(int /*iGeomField */, OGREnvelope *psExtent,
++ bool /*bForce*/) -> OGRErr
+ #else
+-OGRErr OGRGRASSLayer::GetExtent(OGREnvelope *psExtent, int /*bForce*/)
++auto OGRGRASSLayer::GetExtent(OGREnvelope *psExtent, int /*bForce*/) -> OGRErr
+ #endif
+ {
+- struct bound_box box;
++ struct bound_box box
++ {
++ };
+
+ Vect_get_map_box(poMap, &box);
+
+@@ -1106,7 +1088,11 @@ OGRErr OGRGRASSLayer::GetExtent(OGREnvel
+ /************************************************************************/
+ /* TestCapability() */
+ /************************************************************************/
+-int OGRGRASSLayer::TestCapability(const char *pszCap)
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
++auto OGRGRASSLayer::TestCapability(const char *pszCap) const -> int
++#else
++auto OGRGRASSLayer::TestCapability(const char *pszCap) -> int
++#endif
+ {
+ if (EQUAL(pszCap, OLCRandomRead))
+ return TRUE;
+@@ -1130,7 +1116,11 @@ int OGRGRASSLayer::TestCapability(const
+ /************************************************************************/
+ /* GetSpatialRef() */
+ /************************************************************************/
+-OGRSpatialReference *OGRGRASSLayer::GetSpatialRef()
++#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
++auto OGRGRASSLayer::GetSpatialRef() const -> const OGRSpatialReference *
++#else
++auto OGRGRASSLayer::GetSpatialRef() -> OGRSpatialReference *
++#endif
+ {
+ return poSRS;
+ }
=====================================
debian/patches/series
=====================================
@@ -0,0 +1 @@
+gdal-3.12.patch
View it on GitLab: https://salsa.debian.org/debian-gis-team/gdal-grass/-/compare/6b927235b4105f775d76bbc428bed9ddc2b8f790...d7651cabb7847c8d829d01948b7475fd708b4989
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/gdal-grass/-/compare/6b927235b4105f775d76bbc428bed9ddc2b8f790...d7651cabb7847c8d829d01948b7475fd708b4989
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20251025/68befcad/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list