From 39961ec7cc5d1db6bcdd87699257d708983d47b5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 15 Mar 2026 18:45:54 -0400 Subject: [PATCH 01/12] add class member to indicate whether to call fclose() or pclose() --- src/safe_pointers.h | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/safe_pointers.h b/src/safe_pointers.h index 6925d586468..363b513a9f2 100644 --- a/src/safe_pointers.h +++ b/src/safe_pointers.h @@ -26,34 +26,47 @@ namespace LAMMPS_NS { Drop in replacement for ``FILE *``. Use as ``SafeFilePtr fp;`` instead of ``FILE *fp = nullptr;`` and there is no more need to explicitly call -``fclose(fp)``. +``fclose(fp)`` or ``pclose(fp)``. \endverbatim */ class SafeFilePtr { public: - SafeFilePtr() : fp(nullptr) {}; - SafeFilePtr(FILE *_fp) : fp(_fp) {}; + SafeFilePtr() : fp(nullptr), use_pclose(false) {}; + SafeFilePtr(bool _use_pclose) : fp(nullptr), use_pclose(_use_pclose) {}; + SafeFilePtr(FILE *_fp, bool _use_pclose = false) : fp(_fp), use_pclose(_use_pclose) {}; SafeFilePtr(const SafeFilePtr &) = delete; - SafeFilePtr(SafeFilePtr &&o) noexcept : fp(o.fp) { o.fp = nullptr; } + SafeFilePtr(SafeFilePtr &&o) noexcept : fp(o.fp), use_pclose(o.use_pclose) { o.fp = nullptr; } SafeFilePtr &operator=(const SafeFilePtr &) = delete; ~SafeFilePtr() { - if (fp) fclose(fp); + if (fp) { + if (use_pclose) + pclose(fp); + else + fclose(fp); + } } SafeFilePtr &operator=(FILE *_fp) { - if (fp && (fp != _fp)) fclose(fp); + if (fp && (fp != _fp)) { + if (use_pclose) + pclose(fp); + else + fclose(fp); + } fp = _fp; return *this; } + void set_pclose(bool _use_pclose) { use_pclose = _use_pclose; } operator FILE *() const { return fp; } private: FILE *fp; + bool use_pclose; }; } // namespace LAMMPS_NS From 8e0cf35b888a9dddd4d6e59ac655ed85c441e210 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 15 Mar 2026 19:20:53 -0400 Subject: [PATCH 02/12] make use of SafeFilePtr in more places to atomatically close files --- src/ADIOS/dump_atom_adios.cpp | 5 ++-- src/ADIOS/dump_custom_adios.cpp | 4 +-- src/ADIOS/reader_adios.cpp | 4 +-- src/BOCS/fix_bocs.cpp | 4 +-- src/DPD-REACT/fix_eos_table_rx.cpp | 9 ++---- src/DPD-REACT/fix_rx.cpp | 10 ++----- src/DPD-REACT/pair_exp6_rx.cpp | 5 ++-- src/DPD-REACT/pair_multi_lucy.cpp | 4 +-- src/EXTRA-COMMAND/geturl.cpp | 4 +-- src/EXTRA-FIX/fix_ttm.cpp | 4 +-- src/EXTRA-FIX/fix_ttm_grid.cpp | 7 ++--- src/EXTRA-FIX/fix_ttm_mod.cpp | 6 ++-- src/GRAPHICS/fix_graphics_isosurface.cpp | 5 ++-- src/GRAPHICS/fix_graphics_labels.cpp | 7 ++--- src/INTEL/pair_snap_intel.cpp | 12 ++------ src/KOKKOS/pair_exp6_rx_kokkos.cpp | 5 ++-- src/KOKKOS/pair_pod_kokkos.cpp | 7 ++--- src/MACHDYN/fix_smd_wall_surface.cpp | 4 +-- src/MANYBODY/pair_eim.cpp | 5 ++-- src/MBX/fix_mbx.cpp | 6 ++-- src/ML-IAP/mliap_descriptor_snap.cpp | 4 +-- src/ML-IAP/mliap_model_nn.cpp | 5 ++-- src/ML-POD/eapod.cpp | 36 ++++-------------------- src/ML-POD/fitpod_command.cpp | 35 ++++++++--------------- src/ML-POD/pair_pod.cpp | 7 ++--- src/ML-RANN/pair_rann.cpp | 4 +-- src/ML-SNAP/pair_snap.cpp | 12 ++------ src/ORIENT/fix_orient_bcc.cpp | 5 ++-- src/ORIENT/fix_orient_eco.cpp | 4 +-- src/ORIENT/fix_orient_fcc.cpp | 5 ++-- src/PHONON/fix_phonon.cpp | 7 ++--- src/PYTHON/python_impl.cpp | 7 ++--- src/RIGID/fix_rigid.cpp | 4 +-- src/label_map.cpp | 4 +-- src/platform.cpp | 18 ++++-------- src/universe.cpp | 4 +-- src/variable.cpp | 13 +++------ src/write_coeff.cpp | 7 ++--- 38 files changed, 110 insertions(+), 188 deletions(-) diff --git a/src/ADIOS/dump_atom_adios.cpp b/src/ADIOS/dump_atom_adios.cpp index 7e64358adf7..0c2e46ca59c 100644 --- a/src/ADIOS/dump_atom_adios.cpp +++ b/src/ADIOS/dump_atom_adios.cpp @@ -16,11 +16,13 @@ ------------------------------------------------------------------------- */ #include "dump_atom_adios.h" + #include "atom.h" #include "domain.h" #include "error.h" #include "group.h" #include "memory.h" +#include "safe_pointers.h" #include "universe.h" #include "update.h" @@ -53,12 +55,11 @@ class DumpAtomADIOSInternal { DumpAtomADIOS::DumpAtomADIOS(LAMMPS *lmp, int narg, char **arg) : DumpAtom(lmp, narg, arg) { // create a default adios2_config.xml if it doesn't exist yet. - FILE *cfgfp = fopen("adios2_config.xml", "r"); + SafeFilePtr cfgfp = fopen("adios2_config.xml", "r"); if (!cfgfp) { cfgfp = fopen("adios2_config.xml", "w"); if (cfgfp) fputs(default_config, cfgfp); } - if (cfgfp) fclose(cfgfp); internal = new DumpAtomADIOSInternal(); try { diff --git a/src/ADIOS/dump_custom_adios.cpp b/src/ADIOS/dump_custom_adios.cpp index 060a5493f2f..d1f67928b97 100644 --- a/src/ADIOS/dump_custom_adios.cpp +++ b/src/ADIOS/dump_custom_adios.cpp @@ -25,6 +25,7 @@ #include "input.h" #include "memory.h" #include "modify.h" +#include "safe_pointers.h" #include "update.h" #include "variable.h" @@ -61,12 +62,11 @@ class DumpCustomADIOSInternal { DumpCustomADIOS::DumpCustomADIOS(LAMMPS *lmp, int narg, char **arg) : DumpCustom(lmp, narg, arg) { // create a default adios2_config.xml if it doesn't exist yet. - FILE *cfgfp = fopen("adios2_config.xml", "r"); + SafeFilePtr cfgfp = fopen("adios2_config.xml", "r"); if (!cfgfp) { cfgfp = fopen("adios2_config.xml", "w"); if (cfgfp) fputs(default_config, cfgfp); } - if (cfgfp) fclose(cfgfp); internal = new DumpCustomADIOSInternal(); try { diff --git a/src/ADIOS/reader_adios.cpp b/src/ADIOS/reader_adios.cpp index e29f647233f..ac90d652617 100644 --- a/src/ADIOS/reader_adios.cpp +++ b/src/ADIOS/reader_adios.cpp @@ -20,6 +20,7 @@ #include "comm.h" #include "error.h" #include "memory.h" +#include "safe_pointers.h" #include #include @@ -68,12 +69,11 @@ ReaderADIOS::ReaderADIOS(LAMMPS *lmp) : Reader(lmp) me = comm->me; // create a default adios2_config.xml if it doesn't exist yet. - FILE *cfgfp = fopen("adios2_config.xml", "r"); + SafeFilePtr cfgfp = fopen("adios2_config.xml", "r"); if (!cfgfp) { cfgfp = fopen("adios2_config.xml", "w"); if (cfgfp) fputs(default_config, cfgfp); } - if (cfgfp) fclose(cfgfp); internal = new ReadADIOSInternal(); try { diff --git a/src/BOCS/fix_bocs.cpp b/src/BOCS/fix_bocs.cpp index f5fb6f12bf7..94a708d7f3d 100644 --- a/src/BOCS/fix_bocs.cpp +++ b/src/BOCS/fix_bocs.cpp @@ -31,6 +31,7 @@ #include "modify.h" #include "neighbor.h" #include "respa.h" +#include "safe_pointers.h" #include "update.h" #include @@ -568,7 +569,7 @@ int FixBocs::read_F_table(char *filename, int p_basis_type) double **data; bool badInput = false; int numEntries = 0; - FILE *fpi = fopen(filename,"r"); + SafeFilePtr fpi = fopen(filename,"r"); if (fpi) { // Old code read the input file twice. Now we simply // read all the lines from the input file into a string vector, @@ -585,7 +586,6 @@ int FixBocs::read_F_table(char *filename, int p_basis_type) char line[MAX_F_TABLE_LINE_LENGTH] = {'\0'}; std::vector inputLines; while (fgets(line, MAX_F_TABLE_LINE_LENGTH, fpi)) inputLines.emplace_back(line); - fclose(fpi); numEntries = inputLines.size(); if (comm->me == 0) utils::logmesg(lmp, "INFO: Read {} lines from file\n", numEntries); diff --git a/src/DPD-REACT/fix_eos_table_rx.cpp b/src/DPD-REACT/fix_eos_table_rx.cpp index 2b7cfba53fb..b9374b58ce9 100644 --- a/src/DPD-REACT/fix_eos_table_rx.cpp +++ b/src/DPD-REACT/fix_eos_table_rx.cpp @@ -24,6 +24,7 @@ #include "force.h" #include "memory.h" #include "modify.h" +#include "safe_pointers.h" #include #include @@ -305,8 +306,7 @@ void FixEOStableRX::read_file(char *file) // open file on proc 0 - FILE *fp; - fp = nullptr; + SafeFilePtr fp; if (comm->me == 0) { fp = fopen(file,"r"); if (fp == nullptr) { @@ -327,7 +327,6 @@ void FixEOStableRX::read_file(char *file) ptr = fgets(line,MAXLINE,fp); if (ptr == nullptr) { eof = 1; - fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -349,7 +348,6 @@ void FixEOStableRX::read_file(char *file) ptr = fgets(&line[n],MAXLINE-n,fp); if (ptr == nullptr) { eof = 1; - fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -419,7 +417,7 @@ void FixEOStableRX::read_table(Table *tb, Table *tb2, char *file, char *keyword) // open file - FILE *fp = fopen(file,"r"); + SafeFilePtr fp = fopen(file,"r"); if (fp == nullptr) { char str[128]; snprintf(str,128,"Cannot open file %s",file); @@ -500,7 +498,6 @@ void FixEOStableRX::read_table(Table *tb, Table *tb2, char *file, char *keyword) tbl2->efile[i] = rtmp; } } - fclose(fp); } /* ---------------------------------------------------------------------- diff --git a/src/DPD-REACT/fix_rx.cpp b/src/DPD-REACT/fix_rx.cpp index fb96a5853a6..be90f228aef 100644 --- a/src/DPD-REACT/fix_rx.cpp +++ b/src/DPD-REACT/fix_rx.cpp @@ -27,6 +27,7 @@ #include "neigh_list.h" #include "neighbor.h" #include "pair_dpd_fdt_energy.h" +#include "safe_pointers.h" #include "update.h" #include // std::max @@ -238,8 +239,7 @@ void FixRX::post_constructor() // open file on proc 0 - FILE *fp; - fp = nullptr; + SafeFilePtr fp; if (comm->me == 0) { fp = utils::open_potential(kineticsFile,lmp,nullptr); if (fp == nullptr) @@ -259,7 +259,6 @@ void FixRX::post_constructor() ptr = fgets(line,MAXLINE,fp); if (ptr == nullptr) { eof = 1; - fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -775,8 +774,7 @@ void FixRX::read_file(char *file) // open file on proc 0 - FILE *fp; - fp = nullptr; + SafeFilePtr fp; if (comm->me == 0) { fp = utils::open_potential(file,lmp,nullptr); if (fp == nullptr) { @@ -798,7 +796,6 @@ void FixRX::read_file(char *file) ptr = fgets(line,MAXLINE,fp); if (ptr == nullptr) { eof = 1; - fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -851,7 +848,6 @@ void FixRX::read_file(char *file) ptr = fgets(line,MAXLINE,fp); if (ptr == nullptr) { eof = 1; - fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); diff --git a/src/DPD-REACT/pair_exp6_rx.cpp b/src/DPD-REACT/pair_exp6_rx.cpp index 6fcf91ca3bc..2cc7151a19a 100644 --- a/src/DPD-REACT/pair_exp6_rx.cpp +++ b/src/DPD-REACT/pair_exp6_rx.cpp @@ -24,6 +24,7 @@ #include "memory.h" #include "modify.h" #include "neigh_list.h" +#include "safe_pointers.h" #include #include @@ -716,8 +717,7 @@ void PairExp6rx::read_file(char *file) // open file on proc 0 - FILE *fp; - fp = nullptr; + SafeFilePtr fp; if (comm->me == 0) { fp = utils::open_potential(file,lmp,nullptr); if (fp == nullptr) { @@ -740,7 +740,6 @@ void PairExp6rx::read_file(char *file) ptr = fgets(line,MAXLINE,fp); if (ptr == nullptr) { eof = 1; - fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); diff --git a/src/DPD-REACT/pair_multi_lucy.cpp b/src/DPD-REACT/pair_multi_lucy.cpp index 492ed5d0326..0e2739a15eb 100644 --- a/src/DPD-REACT/pair_multi_lucy.cpp +++ b/src/DPD-REACT/pair_multi_lucy.cpp @@ -33,6 +33,7 @@ #include "math_const.h" #include "memory.h" #include "neigh_list.h" +#include "safe_pointers.h" #include #include @@ -350,7 +351,7 @@ void PairMultiLucy::read_table(Table *tb, char *file, char *keyword) // open file - FILE *fp = fopen(file,"r"); + SafeFilePtr fp = fopen(file,"r"); if (fp == nullptr) { char str[128]; snprintf(str,128,"Cannot open file %s",file); @@ -406,7 +407,6 @@ void PairMultiLucy::read_table(Table *tb, char *file, char *keyword) // close file - fclose(fp); } /* ---------------------------------------------------------------------- diff --git a/src/EXTRA-COMMAND/geturl.cpp b/src/EXTRA-COMMAND/geturl.cpp index 03ddde42700..34ad89968a8 100644 --- a/src/EXTRA-COMMAND/geturl.cpp +++ b/src/EXTRA-COMMAND/geturl.cpp @@ -19,6 +19,7 @@ #include "comm.h" #include "error.h" +#include "safe_pointers.h" #include @@ -90,7 +91,7 @@ void GetURL::command(int narg, char **arg) // open output file for writing - FILE *out = fopen(output.c_str(), "wb"); + SafeFilePtr out = fopen(output.c_str(), "wb"); if (!out) error->one(FLERR, "Cannot open output file {} for writing: {}", output, utils::getsyserror()); @@ -125,6 +126,5 @@ void GetURL::command(int narg, char **arg) curl_easy_cleanup(curl); } curl_global_cleanup(); - fclose(out); #endif } diff --git a/src/EXTRA-FIX/fix_ttm.cpp b/src/EXTRA-FIX/fix_ttm.cpp index d79dc1d9b99..3c492c6eb65 100644 --- a/src/EXTRA-FIX/fix_ttm.cpp +++ b/src/EXTRA-FIX/fix_ttm.cpp @@ -29,6 +29,7 @@ #include "potential_file_reader.h" #include "random_mars.h" #include "respa.h" +#include "safe_pointers.h" #include "update.h" #include @@ -518,7 +519,7 @@ void FixTTM::write_electron_temperatures(const std::string &filename) { if (comm->me) return; - FILE *fp = fopen(filename.c_str(),"w"); + SafeFilePtr fp = fopen(filename.c_str(),"w"); if (!fp) error->one(FLERR,"Fix ttm could not open output file {}: {}", filename,utils::getsyserror()); utils::print(fp,"# DATE: {} UNITS: {} COMMENT: Electron temperature on " @@ -532,7 +533,6 @@ void FixTTM::write_electron_temperatures(const std::string &filename) for (ix = 0; ix < nxgrid; ix++) fprintf(fp,"%d %d %d %20.16g\n",ix+1,iy+1,iz+1,T_electron[iz][iy][ix]); - fclose(fp); } /* ---------------------------------------------------------------------- */ diff --git a/src/EXTRA-FIX/fix_ttm_grid.cpp b/src/EXTRA-FIX/fix_ttm_grid.cpp index bd4333b7c50..a9eb20d157e 100644 --- a/src/EXTRA-FIX/fix_ttm_grid.cpp +++ b/src/EXTRA-FIX/fix_ttm_grid.cpp @@ -27,6 +27,7 @@ #include "memory.h" #include "neighbor.h" #include "random_mars.h" +#include "safe_pointers.h" #include "tokenizer.h" #include "update.h" @@ -275,7 +276,7 @@ void FixTTMGrid::read_electron_temperatures(const std::string &filename) // proc 0 opens file - FILE *fp = nullptr; + SafeFilePtr fp; if (comm->me == 0) { fp = utils::open_potential(filename, lmp, nullptr); if (!fp) error->one(FLERR, "Cannot open grid file: {}: {}", filename, utils::getsyserror()); @@ -286,10 +287,6 @@ void FixTTMGrid::read_electron_temperatures(const std::string &filename) grid->read_file(Grid3d::FIX,this,fp,CHUNK,MAXLINE); - // close file - - if (comm->me == 0) fclose(fp); - // check completeness of input data int flag = 0; diff --git a/src/EXTRA-FIX/fix_ttm_mod.cpp b/src/EXTRA-FIX/fix_ttm_mod.cpp index 47f1cc7052b..d5df0f6e280 100644 --- a/src/EXTRA-FIX/fix_ttm_mod.cpp +++ b/src/EXTRA-FIX/fix_ttm_mod.cpp @@ -28,9 +28,10 @@ #include "force.h" #include "math_const.h" #include "memory.h" +#include "potential_file_reader.h" #include "random_mars.h" #include "respa.h" -#include "potential_file_reader.h" +#include "safe_pointers.h" #include "update.h" #include @@ -625,7 +626,7 @@ void FixTTMMod::write_electron_temperatures(const std::string &filename) { if (comm->me) return; - FILE *fp = fopen(filename.c_str(),"w"); + SafeFilePtr fp = fopen(filename.c_str(),"w"); if (!fp) error->one(FLERR,"Fix ttm/mod could not open output file {}: {}", filename, utils::getsyserror()); utils::print(fp,"# DATE: {} UNITS: {} COMMENT: Electron temperature " @@ -642,7 +643,6 @@ void FixTTMMod::write_electron_temperatures(const std::string &filename) fprintf(fp,"%d %d %d %20.16g\n",ix+1,iy+1,iz+1,T_electron[iz][iy][ix]); } - fclose(fp); } /* ---------------------------------------------------------------------- */ diff --git a/src/GRAPHICS/fix_graphics_isosurface.cpp b/src/GRAPHICS/fix_graphics_isosurface.cpp index b57eda59f6b..7b11f7e0f2e 100644 --- a/src/GRAPHICS/fix_graphics_isosurface.cpp +++ b/src/GRAPHICS/fix_graphics_isosurface.cpp @@ -26,6 +26,7 @@ #include "memory.h" #include "modify.h" #include "respa.h" +#include "safe_pointers.h" #include "update.h" #include "variable.h" @@ -923,13 +924,14 @@ void FixGraphicsIsosurface::end_of_step() } } - FILE *fp = nullptr; + SafeFilePtr fp; if (comm->me == 0) { // only MPI rank 0 writes to the file auto *filecurrent = utils::strdup(utils::star_subst(filename, update->ntimestep, pad)); if (platform::has_compress_extension(filename)) { if (binary) error->one(FLERR, Error::NOLASTLINE, "Connot use compression with binary output: {}", filename); + fp.set_pclose(true); fp = platform::compressed_write(filecurrent); } else if (binary) { fp = fopen(filecurrent, "wb"); @@ -1000,7 +1002,6 @@ void FixGraphicsIsosurface::end_of_step() } } if (!binary) fprintf(fp, "endsolid %s\n", title.c_str()); - fclose(fp); // NOLINT delete[] filecurrent; } else { MPI_Send(stldata, 12 * numobjs, MPI_FLOAT, 0, 0, world); diff --git a/src/GRAPHICS/fix_graphics_labels.cpp b/src/GRAPHICS/fix_graphics_labels.cpp index 2c4ee76c099..404284c2d0c 100644 --- a/src/GRAPHICS/fix_graphics_labels.cpp +++ b/src/GRAPHICS/fix_graphics_labels.cpp @@ -24,6 +24,7 @@ #include "modify.h" #include "output.h" #include "respa.h" +#include "safe_pointers.h" #include "text_file_reader.h" #include "tokenizer.h" #include "update.h" @@ -438,14 +439,13 @@ FixGraphicsLabels::FixGraphicsLabels(LAMMPS *lmp, int narg, char **arg) : // must always open in binary mode to avoid data corruption on Windows if (comm->me == 0) { pix.filename = arg[iarg + 1]; - FILE *fp = fopen(pix.filename.c_str(), "rb"); + SafeFilePtr fp = fopen(pix.filename.c_str(), "rb"); if (!fp) error->one(FLERR, iarg + 1, "Cannot open fix graphics/labels image file {}: {}", pix.filename, utils::getsyserror()); pix.timestamp = platform::file_write_time(pix.filename); std::string info; pix.pixmap = read_image(fp, pix.width, pix.height, pix.filename, info); - fclose(fp); if (!pix.pixmap) error->one(FLERR, iarg + 1, "Reading fix graphics/labels image file {} failed: {}", pix.filename, info); @@ -845,13 +845,12 @@ void FixGraphicsLabels::end_of_step() if (pix.timestamp != timestamp) { pix.timestamp = timestamp; - FILE *fp = fopen(pix.filename.c_str(), "rb"); + SafeFilePtr fp = fopen(pix.filename.c_str(), "rb"); if (!fp) error->one(FLERR, Error::NOLASTLINE, "Cannot open fix graphics/labels image file {}: {}", pix.filename, utils::getsyserror()); std::string info; pix.pixmap = read_image(fp, pix.width, pix.height, pix.filename, info); - fclose(fp); if (!pix.pixmap) error->one(FLERR, Error::NOLASTLINE, "Reading fix graphics/labels image file {} failed: {}", pix.filename, info); diff --git a/src/INTEL/pair_snap_intel.cpp b/src/INTEL/pair_snap_intel.cpp index 416f83bd06b..4967e46234f 100644 --- a/src/INTEL/pair_snap_intel.cpp +++ b/src/INTEL/pair_snap_intel.cpp @@ -26,6 +26,7 @@ #include "modify.h" #include "neigh_list.h" #include "neighbor.h" +#include "safe_pointers.h" #include "sna_intel.h" #include "tokenizer.h" @@ -440,7 +441,7 @@ void PairSNAPIntel::read_files(char *coefffilename, char *paramfilename) // open SNAP coefficient file on proc 0 - FILE *fpcoeff; + SafeFilePtr fpcoeff; if (comm->me == 0) { fpcoeff = utils::open_potential(coefffilename,lmp,nullptr); if (fpcoeff == nullptr) @@ -457,7 +458,6 @@ void PairSNAPIntel::read_files(char *coefffilename, char *paramfilename) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -509,7 +509,6 @@ void PairSNAPIntel::read_files(char *coefffilename, char *paramfilename) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -538,7 +537,6 @@ void PairSNAPIntel::read_files(char *coefffilename, char *paramfilename) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } } @@ -565,7 +563,6 @@ void PairSNAPIntel::read_files(char *coefffilename, char *paramfilename) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } @@ -586,8 +583,6 @@ void PairSNAPIntel::read_files(char *coefffilename, char *paramfilename) } } - if (comm->me == 0) fclose(fpcoeff); - for (int jelem = 0; jelem < nelements; jelem++) { if (elementflags[jelem] == 0) error->all(FLERR,"Element {} not found in SNAP coefficient file", elements[jelem]); @@ -620,7 +615,7 @@ void PairSNAPIntel::read_files(char *coefffilename, char *paramfilename) // open SNAP parameter file on proc 0 - FILE *fpparam; + SafeFilePtr fpparam; if (comm->me == 0) { fpparam = utils::open_potential(paramfilename,lmp,nullptr); if (fpparam == nullptr) @@ -634,7 +629,6 @@ void PairSNAPIntel::read_files(char *coefffilename, char *paramfilename) ptr = fgets(line,MAXLINE,fpparam); if (ptr == nullptr) { eof = 1; - fclose(fpparam); } } MPI_Bcast(&eof,1,MPI_INT,0,world); diff --git a/src/KOKKOS/pair_exp6_rx_kokkos.cpp b/src/KOKKOS/pair_exp6_rx_kokkos.cpp index bbbaaaa43fc..40d2b91a472 100644 --- a/src/KOKKOS/pair_exp6_rx_kokkos.cpp +++ b/src/KOKKOS/pair_exp6_rx_kokkos.cpp @@ -26,6 +26,7 @@ #include "memory_kokkos.h" #include "error.h" #include "fix.h" +#include "safe_pointers.h" #include "atom_masks.h" #include "neigh_request.h" #include "atom_kokkos.h" @@ -1697,8 +1698,7 @@ void PairExp6rxKokkos::read_file(char *file) // open file on proc 0 - FILE *fp; - fp = nullptr; + SafeFilePtr fp; if (comm->me == 0) { fp = utils::open_potential(file,lmp,nullptr); if (fp == nullptr) { @@ -1721,7 +1721,6 @@ void PairExp6rxKokkos::read_file(char *file) ptr = fgets(line,MAXLINE,fp); if (ptr == nullptr) { eof = 1; - fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); diff --git a/src/KOKKOS/pair_pod_kokkos.cpp b/src/KOKKOS/pair_pod_kokkos.cpp index 01b6f749111..86ac1c0bb44 100644 --- a/src/KOKKOS/pair_pod_kokkos.cpp +++ b/src/KOKKOS/pair_pod_kokkos.cpp @@ -28,6 +28,7 @@ #include "memory_kokkos.h" #include "neighbor_kokkos.h" #include "neigh_request.h" +#include "safe_pointers.h" #include #include @@ -1780,13 +1781,12 @@ void PairPODKokkos::savematrix2binfile(std::string filename, t_pod_1 auto A = Kokkos::create_mirror_view(d_A); Kokkos::deep_copy(A, d_A); - FILE *fp = fopen(filename.c_str(), "wb"); + SafeFilePtr fp = fopen(filename.c_str(), "wb"); double sz[2]; sz[0] = (double) nrows; sz[1] = (double) ncols; fwrite( reinterpret_cast( sz ), sizeof(double) * (2), 1, fp); fwrite( reinterpret_cast( A.data() ), sizeof(double) * (nrows*ncols), 1, fp); - fclose(fp); } template @@ -1795,13 +1795,12 @@ void PairPODKokkos::saveintmatrix2binfile(std::string filename, t_po auto A = Kokkos::create_mirror_view(d_A); Kokkos::deep_copy(A, d_A); - FILE *fp = fopen(filename.c_str(), "wb"); + SafeFilePtr fp = fopen(filename.c_str(), "wb"); int sz[2]; sz[0] = nrows; sz[1] = ncols; fwrite( reinterpret_cast( sz ), sizeof(int) * (2), 1, fp); fwrite( reinterpret_cast( A.data() ), sizeof(int) * (nrows*ncols), 1, fp); - fclose(fp); } template diff --git a/src/MACHDYN/fix_smd_wall_surface.cpp b/src/MACHDYN/fix_smd_wall_surface.cpp index 04851d1c740..492c3263a6e 100644 --- a/src/MACHDYN/fix_smd_wall_surface.cpp +++ b/src/MACHDYN/fix_smd_wall_surface.cpp @@ -24,6 +24,7 @@ #include "error.h" #include "graphics.h" #include "memory.h" +#include "safe_pointers.h" #include "text_file_reader.h" #include @@ -188,7 +189,7 @@ void FixSMDWallSurface::read_triangles(int pass) vert = new Vector3d[3]; Vector3d normal, center; - FILE *fp = fopen(filename, "r"); + SafeFilePtr fp = fopen(filename, "r"); if (fp == nullptr) error->one(FLERR, "Cannot open file {}: {}", filename, utils::getsyserror()); if (comm->me == 0) { @@ -331,7 +332,6 @@ void FixSMDWallSurface::read_triangles(int pass) } delete[] vert; - fclose(fp); } /* ---------------------------------------------------------------------- diff --git a/src/MANYBODY/pair_eim.cpp b/src/MANYBODY/pair_eim.cpp index 6cb7ea674a4..520ccdc51e9 100644 --- a/src/MANYBODY/pair_eim.cpp +++ b/src/MANYBODY/pair_eim.cpp @@ -25,6 +25,7 @@ #include "memory.h" #include "neigh_list.h" #include "neighbor.h" +#include "safe_pointers.h" #include "tokenizer.h" #include @@ -1009,7 +1010,7 @@ EIMPotentialFileReader::EIMPotentialFileReader(LAMMPS *lmp, } int unit_convert = auto_convert; - FILE *fp = utils::open_potential(filename, lmp, &unit_convert); + SafeFilePtr fp = utils::open_potential(filename, lmp, &unit_convert); conversion_factor = utils::get_conversion_factor(utils::ENERGY,unit_convert); if (fp == nullptr) { @@ -1017,8 +1018,6 @@ EIMPotentialFileReader::EIMPotentialFileReader(LAMMPS *lmp, } parse(fp); - - fclose(fp); } std::pair EIMPotentialFileReader::get_pair(const std::string &a, const std::string &b) { diff --git a/src/MBX/fix_mbx.cpp b/src/MBX/fix_mbx.cpp index f163dee0ad9..c53f9cf98ad 100644 --- a/src/MBX/fix_mbx.cpp +++ b/src/MBX/fix_mbx.cpp @@ -28,6 +28,7 @@ #include "pair.h" #include "pair_mbx.h" #include "respa.h" +#include "safe_pointers.h" #include "universe.h" #include "update.h" @@ -480,11 +481,10 @@ FixMBX::FixMBX(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) int size = 0; if (me == 0) { // Test if file present - FILE *fp = fopen(json_file.c_str(), "r"); + SafeFilePtr fp = fopen(json_file.c_str(), "r"); if (fp == NULL) { error->one(FLERR, "Cannot open file " + json_file); - } else - fclose(fp); + } std::ifstream t(json_file); t.seekg(0, std::ios::end); diff --git a/src/ML-IAP/mliap_descriptor_snap.cpp b/src/ML-IAP/mliap_descriptor_snap.cpp index 90590d50d4b..5750cbe402b 100644 --- a/src/ML-IAP/mliap_descriptor_snap.cpp +++ b/src/ML-IAP/mliap_descriptor_snap.cpp @@ -23,6 +23,7 @@ #include "memory.h" #include "mliap_data.h" #include "pair_mliap.h" +#include "safe_pointers.h" #include "sna.h" #include "tokenizer.h" @@ -373,7 +374,7 @@ void MLIAPDescriptorSNAP::read_paramfile(char *paramfilename) // open SNAP parameter file on proc 0 - FILE *fpparam; + SafeFilePtr fpparam; if (comm->me == 0) { fpparam = utils::open_potential(paramfilename, lmp, nullptr); if (fpparam == nullptr) @@ -391,7 +392,6 @@ void MLIAPDescriptorSNAP::read_paramfile(char *paramfilename) ptr = fgets(line, MAXLINE, fpparam); if (ptr == nullptr) { eof = 1; - fclose(fpparam); } else n = strlen(line) + 1; } diff --git a/src/ML-IAP/mliap_model_nn.cpp b/src/ML-IAP/mliap_model_nn.cpp index 2273594c5b4..90746d14c6d 100644 --- a/src/ML-IAP/mliap_model_nn.cpp +++ b/src/ML-IAP/mliap_model_nn.cpp @@ -22,6 +22,7 @@ #include "comm.h" #include "error.h" #include "memory.h" +#include "safe_pointers.h" #include "tokenizer.h" #include @@ -67,7 +68,7 @@ void MLIAPModelNN::read_coeffs(char *coefffilename) // open coefficient file on proc 0 - FILE *fpcoeff; + SafeFilePtr fpcoeff; if (comm->me == 0) { fpcoeff = utils::open_potential(coefffilename, lmp, nullptr); if (fpcoeff == nullptr) @@ -83,7 +84,6 @@ void MLIAPModelNN::read_coeffs(char *coefffilename) ptr = fgets(line, MAXLINE, fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } else n = strlen(line) + 1; } @@ -124,7 +124,6 @@ void MLIAPModelNN::read_coeffs(char *coefffilename) ptr = fgets(line, MAXLINE, fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } else n = strlen(line) + 1; } diff --git a/src/ML-POD/eapod.cpp b/src/ML-POD/eapod.cpp index 94eba64c4d1..b309224e0c2 100644 --- a/src/ML-POD/eapod.cpp +++ b/src/ML-POD/eapod.cpp @@ -23,6 +23,7 @@ #include "math_const.h" #include "math_special.h" #include "memory.h" +#include "safe_pointers.h" #include "tokenizer.h" #include @@ -134,7 +135,7 @@ EAPOD::~EAPOD() void EAPOD::read_pod_file(const std::string &pod_file) { std::string podfilename = pod_file; - FILE *fppod; + SafeFilePtr fppod; if (comm->me == 0) { fppod = utils::open_potential(podfilename,lmp,nullptr); @@ -153,7 +154,6 @@ void EAPOD::read_pod_file(const std::string &pod_file) ptr = fgets(line,MAXLINE,fppod); if (ptr == nullptr) { eof = 1; - fclose(fppod); } } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -402,7 +402,7 @@ void EAPOD::read_pod_file(const std::string &pod_file) void EAPOD::read_model_coeff_file(const std::string &coeff_file) { std::string coefffilename = coeff_file; - FILE *fpcoeff; + SafeFilePtr fpcoeff; if (comm->me == 0) { fpcoeff = utils::open_potential(coefffilename,lmp,nullptr); @@ -420,7 +420,6 @@ void EAPOD::read_model_coeff_file(const std::string &coeff_file) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -457,7 +456,6 @@ void EAPOD::read_model_coeff_file(const std::string &coeff_file) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } @@ -482,7 +480,6 @@ void EAPOD::read_model_coeff_file(const std::string &coeff_file) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } @@ -507,7 +504,6 @@ void EAPOD::read_model_coeff_file(const std::string &coeff_file) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } @@ -525,10 +521,6 @@ void EAPOD::read_model_coeff_file(const std::string &coeff_file) } } - if (comm->me == 0) { - if (!eof) fclose(fpcoeff); - } - if (ncoeffall != nCoeffAll) error->all(FLERR,"number of coefficients in the coefficient file is not correct"); @@ -553,7 +545,7 @@ void EAPOD::read_model_coeff_file(const std::string &coeff_file) int EAPOD::read_coeff_file(const std::string &coeff_file) { std::string coefffilename = coeff_file; - FILE *fpcoeff; + SafeFilePtr fpcoeff; if (comm->me == 0) { fpcoeff = utils::open_potential(coefffilename,lmp,nullptr); @@ -572,7 +564,6 @@ int EAPOD::read_coeff_file(const std::string &coeff_file) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -608,7 +599,6 @@ int EAPOD::read_coeff_file(const std::string &coeff_file) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } @@ -628,10 +618,6 @@ int EAPOD::read_coeff_file(const std::string &coeff_file) } } - if (comm->me == 0) { - if (!eof) fclose(fpcoeff); - } - if (comm->me == 0) { utils::logmesg(lmp, "**************** Begin of POD Coefficients ****************\n"); utils::logmesg(lmp, "total number of coefficients for POD potential: {}\n", ncoeffall); @@ -645,7 +631,7 @@ int EAPOD::read_coeff_file(const std::string &coeff_file) int EAPOD::read_projection_matrix(const std::string &proj_file) { std::string projfilename = proj_file; - FILE *fpproj; + SafeFilePtr fpproj; if (comm->me == 0) { fpproj = utils::open_potential(projfilename,lmp,nullptr); @@ -664,7 +650,6 @@ int EAPOD::read_projection_matrix(const std::string &proj_file) ptr = fgets(line,MAXLINE,fpproj); if (ptr == nullptr) { eof = 1; - fclose(fpproj); } } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -700,7 +685,6 @@ int EAPOD::read_projection_matrix(const std::string &proj_file) ptr = fgets(line,MAXLINE,fpproj); if (ptr == nullptr) { eof = 1; - fclose(fpproj); } } @@ -719,9 +703,6 @@ int EAPOD::read_projection_matrix(const std::string &proj_file) error->all(FLERR,"Incorrect format in PCA projection matrix file: {}", e.what()); } } - if (comm->me == 0) { - if (!eof) fclose(fpproj); - } if (comm->me == 0) { utils::logmesg(lmp, "**************** Begin of PCA projection matrix ****************\n"); @@ -736,7 +717,7 @@ int EAPOD::read_projection_matrix(const std::string &proj_file) int EAPOD::read_centroids(const std::string ¢roids_file) { std::string centfilename = centroids_file; - FILE *fpcent; + SafeFilePtr fpcent; if (comm->me == 0) { fpcent = utils::open_potential(centfilename,lmp,nullptr); @@ -755,7 +736,6 @@ int EAPOD::read_centroids(const std::string ¢roids_file) ptr = fgets(line,MAXLINE,fpcent); if (ptr == nullptr) { eof = 1; - fclose(fpcent); } } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -791,7 +771,6 @@ int EAPOD::read_centroids(const std::string ¢roids_file) ptr = fgets(line,MAXLINE,fpcent); if (ptr == nullptr) { eof = 1; - fclose(fpcent); } } @@ -810,9 +789,6 @@ int EAPOD::read_centroids(const std::string ¢roids_file) error->all(FLERR,"Incorrect format in PCA centroids file: {}", e.what()); } } - if (comm->me == 0) { - if (!eof) fclose(fpcent); - } if (comm->me == 0) { utils::logmesg(lmp, "**************** Begin of PCA centroids ****************\n"); diff --git a/src/ML-POD/fitpod_command.cpp b/src/ML-POD/fitpod_command.cpp index 9e9c7fa47b0..b5d8b41f46b 100644 --- a/src/ML-POD/fitpod_command.cpp +++ b/src/ML-POD/fitpod_command.cpp @@ -20,6 +20,7 @@ #include "comm.h" #include "error.h" #include "memory.h" +#include "safe_pointers.h" #include "tokenizer.h" #include @@ -280,7 +281,7 @@ int FitPOD::read_data_file(double *fitting_weights, std::string &file_format, int precision = 8; std::string datafilename = data_file; - FILE *fpdata; + SafeFilePtr fpdata; if (comm->me == 0) { fpdata = utils::open_potential(datafilename, lmp, nullptr); @@ -297,7 +298,6 @@ int FitPOD::read_data_file(double *fitting_weights, std::string &file_format, ptr = fgets(line, MAXLINE, fpdata); if (ptr == nullptr) { eof = 1; - fclose(fpdata); } } MPI_Bcast(&eof, 1, MPI_INT, 0, world); @@ -459,7 +459,7 @@ void FitPOD::get_exyz_files(std::vector &files, std::vector &num_atom, int &num_atom_sum, std::string file) { std::string filename = std::move(file); - FILE *fp; + SafeFilePtr fp; if (comm->me == 0) { fp = utils::open_potential(filename, lmp, nullptr); if (fp == nullptr) @@ -478,7 +478,6 @@ int FitPOD::get_number_atom_exyz(std::vector &num_atom, int &num_atom_sum, ptr = fgets(line, MAXLINE, fp); if (ptr == nullptr) { eof = 1; - fclose(fp); } } MPI_Bcast(&eof, 1, MPI_INT, 0, world); @@ -532,7 +531,7 @@ void FitPOD::read_exyz_file(double *lattice, double *stress, double *energy, dou { std::string filename = std::move(file); - FILE *fp; + SafeFilePtr fp; if (comm->me == 0) { fp = utils::open_potential(filename, lmp, nullptr); if (fp == nullptr) @@ -552,7 +551,6 @@ void FitPOD::read_exyz_file(double *lattice, double *stress, double *energy, dou ptr = fgets(line, MAXLINE, fp); if (ptr == nullptr) { eof = 1; - fclose(fp); } } MPI_Bcast(&eof, 1, MPI_INT, 0, world); @@ -1346,29 +1344,27 @@ void FitPOD::descriptors_calculation(const datastruct &data) std::string filename0 = data.data_path + "/basedescriptors_config" + std::to_string(ci + 1) + ".bin"; - FILE *fp0 = fopen(filename0.c_str(), "wb"); + SafeFilePtr fp0 = fopen(filename0.c_str(), "wb"); sz[0] = (double) data.num_atom[ci]; sz[1] = (double) fastpodptr->Mdesc; fwrite(reinterpret_cast(sz), sizeof(double) * (2), 1, fp0); fwrite(reinterpret_cast(desc.bd), sizeof(double) * (data.num_atom[ci] * fastpodptr->Mdesc), 1, fp0); - fclose(fp0); if (desc.nClusters > 1) { std::string filename1 = data.data_path + "/environmentdescriptors_config" + std::to_string(ci + 1) + ".bin"; - FILE *fp1 = fopen(filename1.c_str(), "wb"); + SafeFilePtr fp1 = fopen(filename1.c_str(), "wb"); sz[0] = (double) data.num_atom[ci]; sz[1] = (double) fastpodptr->nClusters; fwrite(reinterpret_cast(sz), sizeof(double) * (2), 1, fp1); fwrite(reinterpret_cast(desc.pd), sizeof(double) * (data.num_atom[ci] * fastpodptr->nClusters), 1, fp1); - fclose(fp1); } std::string filename = data.data_path + "/globaldescriptors_config" + std::to_string(ci + 1) + ".bin"; - FILE *fp = fopen(filename.c_str(), "wb"); + SafeFilePtr fp = fopen(filename.c_str(), "wb"); sz[0] = (double) data.num_atom[ci]; sz[1] = (double) desc.nCoeffAll; @@ -1378,7 +1374,6 @@ void FitPOD::descriptors_calculation(const datastruct &data) fwrite(reinterpret_cast(desc.gdd), sizeof(double) * (3 * data.num_atom[ci] * desc.nCoeffAll), 1, fp); } - fclose(fp); } } @@ -1637,13 +1632,12 @@ void FitPOD::least_squares_fit(const datastruct &data) if (save_descriptors > 0) { std::string filename = data.data_path + "/descriptors_config" + std::to_string(ci + 1) + ".bin"; - FILE *fp = fopen(filename.c_str(), "wb"); + SafeFilePtr fp = fopen(filename.c_str(), "wb"); fwrite(reinterpret_cast(desc.gd), sizeof(double) * (desc.nCoeffAll), 1, fp); if (save_descriptors == 2) { fwrite(reinterpret_cast(desc.gdd), sizeof(double) * (3 * data.num_atom[ci] * desc.nCoeffAll), 1, fp); } - fclose(fp); } // assemble the least-squares linear system @@ -1965,11 +1959,9 @@ void FitPOD::energyforce_calculation(const datastruct &data) force[0] = energy; std::string filename = "energyforce_config" + std::to_string(ci + 1) + ".bin"; - FILE *fp = fopen(filename.c_str(), "wb"); + SafeFilePtr fp = fopen(filename.c_str(), "wb"); fwrite(reinterpret_cast(force.data()), sizeof(double) * (1 + nforce), 1, fp); - - fclose(fp); } ci += 1; } @@ -2226,24 +2218,22 @@ void FitPOD::KmeansClustering(double *points, double *centroids, int *assignment void FitPOD::savematrix2binfile(const std::string &filename, double *A, int nrows, int ncols) { - FILE *fp = fopen(filename.c_str(), "wb"); + SafeFilePtr fp = fopen(filename.c_str(), "wb"); double sz[2]; sz[0] = (double) nrows; sz[1] = (double) ncols; fwrite(reinterpret_cast(sz), sizeof(double) * (2), 1, fp); fwrite(reinterpret_cast(A), sizeof(double) * (nrows * ncols), 1, fp); - fclose(fp); } void FitPOD::saveintmatrix2binfile(const std::string &filename, int *A, int nrows, int ncols) { - FILE *fp = fopen(filename.c_str(), "wb"); + SafeFilePtr fp = fopen(filename.c_str(), "wb"); int sz[2]; sz[0] = nrows; sz[1] = ncols; fwrite(reinterpret_cast(sz), sizeof(int) * (2), 1, fp); fwrite(reinterpret_cast(A), sizeof(int) * (nrows * ncols), 1, fp); - fclose(fp); } void FitPOD::savedata2textfile(const std::string &filename, const std::string &text, double *A, @@ -2251,7 +2241,7 @@ void FitPOD::savedata2textfile(const std::string &filename, const std::string &t { if (comm->me == 0) { int precision = 15; - FILE *fp = fopen(filename.c_str(), "w"); + SafeFilePtr fp = fopen(filename.c_str(), "w"); if (dim == 1) { utils::print(fp, text, n); for (int i = 0; i < n; i++) utils::print(fp, "{:<10.{}f} \n", A[i], precision); @@ -2263,6 +2253,5 @@ void FitPOD::savedata2textfile(const std::string &filename, const std::string &t utils::print(fp, " \n"); } } - fclose(fp); } } diff --git a/src/ML-POD/pair_pod.cpp b/src/ML-POD/pair_pod.cpp index 2e5b635490b..15f8508cdcc 100644 --- a/src/ML-POD/pair_pod.cpp +++ b/src/ML-POD/pair_pod.cpp @@ -26,6 +26,7 @@ #include "memory.h" #include "neigh_list.h" #include "neighbor.h" +#include "safe_pointers.h" #include #include @@ -2112,24 +2113,22 @@ void PairPOD::blockatomenergyforce(double *ei, double *fij, int Ni, int Nij) void PairPOD::savematrix2binfile(const std::string &filename, double *A, int nrows, int ncols) { - FILE *fp = fopen(filename.c_str(), "wb"); + SafeFilePtr fp = fopen(filename.c_str(), "wb"); double sz[2]; sz[0] = (double) nrows; sz[1] = (double) ncols; fwrite( reinterpret_cast( sz ), sizeof(double) * (2), 1, fp); fwrite( reinterpret_cast( A ), sizeof(double) * (nrows*ncols), 1, fp); - fclose(fp); } void PairPOD::saveintmatrix2binfile(const std::string &filename, int *A, int nrows, int ncols) { - FILE *fp = fopen(filename.c_str(), "wb"); + SafeFilePtr fp = fopen(filename.c_str(), "wb"); int sz[2]; sz[0] = nrows; sz[1] = ncols; fwrite( reinterpret_cast( sz ), sizeof(int) * (2), 1, fp); fwrite( reinterpret_cast( A ), sizeof(int) * (nrows*ncols), 1, fp); - fclose(fp); } void PairPOD::savedatafordebugging() diff --git a/src/ML-RANN/pair_rann.cpp b/src/ML-RANN/pair_rann.cpp index 3f290acc67b..c588539b7e8 100644 --- a/src/ML-RANN/pair_rann.cpp +++ b/src/ML-RANN/pair_rann.cpp @@ -38,6 +38,7 @@ DISTRIBUTION A. Approved for public release; distribution unlimited. OPSEC#4918 #include "memory.h" #include "neighbor.h" #include "neigh_list.h" +#include "safe_pointers.h" #include "tokenizer.h" #include "update.h" @@ -349,7 +350,7 @@ void PairRANN::coeff(int narg, char **arg) void PairRANN::read_file(char *filename) { - FILE *fp; + SafeFilePtr fp; int eof = 0; std::string line,line1; const int longline = 4096; @@ -373,7 +374,6 @@ void PairRANN::read_file(char *filename) ptr=fgets(linetemp,longline,fp); linenum++; if (ptr == nullptr) { - fclose(fp); if (check_potential()) { error->one(FLERR,"Invalid syntax in potential file, values are inconsistent or missing"); } diff --git a/src/ML-SNAP/pair_snap.cpp b/src/ML-SNAP/pair_snap.cpp index 53734fa35c9..68d9fe83354 100644 --- a/src/ML-SNAP/pair_snap.cpp +++ b/src/ML-SNAP/pair_snap.cpp @@ -22,6 +22,7 @@ #include "memory.h" #include "neigh_list.h" #include "neighbor.h" +#include "safe_pointers.h" #include "sna.h" #include "tokenizer.h" @@ -468,7 +469,7 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) // open SNAP coefficient file on proc 0 - FILE *fpcoeff; + SafeFilePtr fpcoeff; if (comm->me == 0) { fpcoeff = utils::open_potential(coefffilename,lmp,nullptr); if (fpcoeff == nullptr) @@ -485,7 +486,6 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -537,7 +537,6 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } MPI_Bcast(&eof,1,MPI_INT,0,world); @@ -566,7 +565,6 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } } @@ -593,7 +591,6 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; - fclose(fpcoeff); } } @@ -614,8 +611,6 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) } } - if (comm->me == 0) fclose(fpcoeff); - for (int jelem = 0; jelem < nelements; jelem++) { if (elementflags[jelem] == 0) error->all(FLERR,"Element {} not found in SNAP coefficient file", elements[jelem]); @@ -648,7 +643,7 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) // open SNAP parameter file on proc 0 - FILE *fpparam; + SafeFilePtr fpparam; if (comm->me == 0) { fpparam = utils::open_potential(paramfilename,lmp,nullptr); if (fpparam == nullptr) @@ -662,7 +657,6 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) ptr = fgets(line,MAXLINE,fpparam); if (ptr == nullptr) { eof = 1; - fclose(fpparam); } } MPI_Bcast(&eof,1,MPI_INT,0,world); diff --git a/src/ORIENT/fix_orient_bcc.cpp b/src/ORIENT/fix_orient_bcc.cpp index 70a14f7c7ec..cf592f99ccc 100644 --- a/src/ORIENT/fix_orient_bcc.cpp +++ b/src/ORIENT/fix_orient_bcc.cpp @@ -30,6 +30,7 @@ #include "neigh_list.h" #include "neighbor.h" #include "respa.h" +#include "safe_pointers.h" #include "update.h" #include @@ -104,7 +105,7 @@ FixOrientBCC::FixOrientBCC(LAMMPS *lmp, int narg, char **arg) : char *result; int count; - FILE *inpfile = fopen(xifilename,"r"); + SafeFilePtr inpfile = fopen(xifilename,"r"); if (inpfile == nullptr) error->one(FLERR,"Fix orient/bcc file open failed"); for (int i = 0; i < half_bcc_nn; i++) { result = fgets(line,IMGMAX,inpfile); @@ -112,7 +113,6 @@ FixOrientBCC::FixOrientBCC(LAMMPS *lmp, int narg, char **arg) : count = sscanf(line,"%lg %lg %lg",&Rxi[i][0],&Rxi[i][1],&Rxi[i][2]); if (count != 3) error->one(FLERR,"Fix orient/bcc file read failed"); } - fclose(inpfile); inpfile = fopen(chifilename,"r"); if (inpfile == nullptr) error->one(FLERR,"Fix orient/bcc file open failed"); @@ -122,7 +122,6 @@ FixOrientBCC::FixOrientBCC(LAMMPS *lmp, int narg, char **arg) : count = sscanf(line,"%lg %lg %lg",&Rchi[i][0],&Rchi[i][1],&Rchi[i][2]); if (count != 3) error->one(FLERR,"Fix orient/bcc file read failed"); } - fclose(inpfile); } MPI_Bcast(&Rxi[0][0],half_bcc_nn*3,MPI_DOUBLE,0,world); diff --git a/src/ORIENT/fix_orient_eco.cpp b/src/ORIENT/fix_orient_eco.cpp index f1a45773e75..3a0d8266cfb 100644 --- a/src/ORIENT/fix_orient_eco.cpp +++ b/src/ORIENT/fix_orient_eco.cpp @@ -29,6 +29,7 @@ #include "neighbor.h" #include "pair.h" #include "respa.h" +#include "safe_pointers.h" #include "update.h" #include @@ -92,7 +93,7 @@ FixOrientECO::FixOrientECO(LAMMPS *lmp, int narg, char **arg) : char *result; int count; - FILE *infile = utils::open_potential(dir_filename,lmp,nullptr); + SafeFilePtr infile = utils::open_potential(dir_filename,lmp,nullptr); if (infile == nullptr) error->one(FLERR,"Cannot open fix orient/eco file {}: {}", dir_filename, utils::getsyserror()); @@ -102,7 +103,6 @@ FixOrientECO::FixOrientECO(LAMMPS *lmp, int narg, char **arg) : count = sscanf(line, "%lg %lg %lg", &dir_vec[i][0], &dir_vec[i][1], &dir_vec[i][2]); if (count != 3) error->one(FLERR, "Fix orient/eco file read failed"); } - fclose(infile); // calculate reciprocal lattice vectors get_reciprocal(); diff --git a/src/ORIENT/fix_orient_fcc.cpp b/src/ORIENT/fix_orient_fcc.cpp index af487121539..5329c50ed6e 100644 --- a/src/ORIENT/fix_orient_fcc.cpp +++ b/src/ORIENT/fix_orient_fcc.cpp @@ -27,6 +27,7 @@ #include "neigh_list.h" #include "neighbor.h" #include "respa.h" +#include "safe_pointers.h" #include "update.h" #include @@ -101,7 +102,7 @@ FixOrientFCC::FixOrientFCC(LAMMPS *lmp, int narg, char **arg) : char *result; int count; - FILE *inpfile = fopen(xifilename,"r"); + SafeFilePtr inpfile = fopen(xifilename,"r"); if (inpfile == nullptr) error->one(FLERR,"Fix orient/fcc file open failed"); for (int i = 0; i < half_fcc_nn; i++) { result = fgets(line,IMGMAX,inpfile); @@ -109,7 +110,6 @@ FixOrientFCC::FixOrientFCC(LAMMPS *lmp, int narg, char **arg) : count = sscanf(line,"%lg %lg %lg",&Rxi[i][0],&Rxi[i][1],&Rxi[i][2]); if (count != 3) error->one(FLERR,"Fix orient/fcc file read failed"); } - fclose(inpfile); inpfile = fopen(chifilename,"r"); if (inpfile == nullptr) error->one(FLERR,"Fix orient/fcc file open failed"); @@ -119,7 +119,6 @@ FixOrientFCC::FixOrientFCC(LAMMPS *lmp, int narg, char **arg) : count = sscanf(line,"%lg %lg %lg",&Rchi[i][0],&Rchi[i][1],&Rchi[i][2]); if (count != 3) error->one(FLERR,"Fix orient/fcc file read failed"); } - fclose(inpfile); } MPI_Bcast(&Rxi[0][0],half_fcc_nn*3,MPI_DOUBLE,0,world); diff --git a/src/PHONON/fix_phonon.cpp b/src/PHONON/fix_phonon.cpp index 53c1987ba8d..6bb39714e72 100644 --- a/src/PHONON/fix_phonon.cpp +++ b/src/PHONON/fix_phonon.cpp @@ -36,6 +36,7 @@ #include "group.h" #include "memory.h" #include "modify.h" +#include "safe_pointers.h" #include "tokenizer.h" #include "update.h" @@ -556,7 +557,7 @@ void FixPhonon::readmap() // read from map file for others char line[MAXLINE] = {'\0'}; - FILE *fp = fopen(mapfile, "r"); + SafeFilePtr fp = fopen(mapfile, "r"); if (fp == nullptr) error->all(FLERR,"Cannot open input map file {}: {}", mapfile, utils::getsyserror()); @@ -605,7 +606,6 @@ void FixPhonon::readmap() } catch (TokenizerException &e) { error->all(FLERR, "Incorrect map file format: {}", e.what()); } - fclose(fp); if (tag2surf.size() != surf2tag.size() || tag2surf.size() != static_cast(ngroup) ) @@ -717,7 +717,7 @@ void FixPhonon::postprocess( ) // write binary file, in fact, it is the force constants matrix that is written // Enforcement of ASR and the conversion of dynamical matrix is done in the postprocessing code auto fname = fmt::format("{}.bin.{}",prefix,update->ntimestep); - FILE *fp_bin = fopen(fname.c_str(),"wb"); + SafeFilePtr fp_bin = fopen(fname.c_str(),"wb"); fwrite(&sysdim, sizeof(int), 1, fp_bin); fwrite(&nx, sizeof(int), 1, fp_bin); @@ -734,7 +734,6 @@ void FixPhonon::postprocess( ) fwrite(basetype, sizeof(int), nucell, fp_bin); fwrite(M_inv_sqrt, sizeof(double),nucell, fp_bin); - fclose(fp_bin); // write log file, here however, it is the dynamical matrix that is written utils::print(flog,"############################################################\n"); diff --git a/src/PYTHON/python_impl.cpp b/src/PYTHON/python_impl.cpp index c47b2b8de99..ece261840bc 100644 --- a/src/PYTHON/python_impl.cpp +++ b/src/PYTHON/python_impl.cpp @@ -23,6 +23,7 @@ #include "memory.h" #include "python_compat.h" #include "python_utils.h" +#include "safe_pointers.h" #include "variable.h" #include // IWYU pragma: export @@ -291,7 +292,7 @@ void PythonImpl::command(int narg, char **arg) // exist: do nothing, assume code has already been run if (pyfile) { - FILE *fp = fopen(pyfile, "r"); + SafeFilePtr fp = fopen(pyfile, "r"); if (fp == nullptr) { PyUtils::Print_Errors(); @@ -303,7 +304,6 @@ void PythonImpl::command(int narg, char **arg) PyUtils::Print_Errors(); error->all(FLERR, Error::NOLASTLINE, "Could not process Python file: {}", pyfile); } - fclose(fp); } else if (herestr) { int err = PyRun_SimpleString(herestr); @@ -685,14 +685,13 @@ int PythonImpl::execute_string(char *cmd) int PythonImpl::execute_file(char *fname) { - FILE *fp = fopen(fname, "r"); + SafeFilePtr fp = fopen(fname, "r"); if (fp == nullptr) return -1; PyUtils::GIL lock; int err = PyRun_SimpleFile(fp, fname); if (err) PyUtils::Print_Errors(); - if (fp) fclose(fp); return err; } diff --git a/src/RIGID/fix_rigid.cpp b/src/RIGID/fix_rigid.cpp index 46d93ba8dfd..08a4ab2103b 100644 --- a/src/RIGID/fix_rigid.cpp +++ b/src/RIGID/fix_rigid.cpp @@ -31,6 +31,7 @@ #include "random_mars.h" #include "respa.h" #include "rigid_const.h" +#include "safe_pointers.h" #include "tokenizer.h" #include "update.h" #include "variable.h" @@ -2385,7 +2386,7 @@ void FixRigid::write_restart_file(const char *file) if (comm->me) return; auto outfile = std::string(file) + ".rigid"; - FILE *fp = fopen(outfile.c_str(),"w"); + SafeFilePtr fp = fopen(outfile.c_str(),"w"); if (fp == nullptr) error->one(FLERR,"Cannot open fix rigid restart file {}: {}",outfile,utils::getsyserror()); @@ -2419,7 +2420,6 @@ void FixRigid::write_restart_file(const char *file) angmom[i][0],angmom[i][1],angmom[i][2],xbox,ybox,zbox); } - fclose(fp); } /* ---------------------------------------------------------------------- diff --git a/src/label_map.cpp b/src/label_map.cpp index c05aec0d41e..f6572e22c61 100644 --- a/src/label_map.cpp +++ b/src/label_map.cpp @@ -19,6 +19,7 @@ #include "error.h" #include "force.h" #include "improper.h" +#include "safe_pointers.h" #include "tokenizer.h" #include @@ -746,7 +747,7 @@ int LabelMap::read_int(FILE *fp) void LabelMap::write_map(const std::string &filename) { if (comm->me == 0) { - FILE *fp = fopen(filename.c_str(), "w"); + SafeFilePtr fp = fopen(filename.c_str(), "w"); if (!fp) error->one(FLERR, "Cannot open label map file {}: {}", filename, utils::getsyserror()); if (typelabel_map.size() > 0) { fputs("labelmap atom", fp); @@ -778,6 +779,5 @@ void LabelMap::write_map(const std::string &filename) if (!itypelabel[i].empty()) utils::print(fp, R"( {} """ {} """)", i + 1, itypelabel[i]); fputc('\n', fp); } - fclose(fp); } } diff --git a/src/platform.cpp b/src/platform.cpp index 7032e6341a0..e5f7b82949d 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -974,11 +974,8 @@ std::string platform::path_join(const std::string &a, const std::string &b) bool platform::file_is_readable(const std::string &path) { - FILE *fp = fopen(path.c_str(), "r"); - if (fp) { - fclose(fp); - return true; - } + SafeFilePtr fp = fopen(path.c_str(), "r"); + if (fp) return true; return false; } @@ -990,16 +987,13 @@ bool platform::file_is_writable(const std::string &path) { // if the file exists, try to append and don't delete + SafeFilePtr fp; if (file_is_readable(path)) { - FILE *fp = fopen(path.c_str(), "a"); - if (fp) { - fclose(fp); - return true; - } + fp = fopen(path.c_str(), "a"); + if (fp) return true; } else { - FILE *fp = fopen(path.c_str(), "w"); + fp = fopen(path.c_str(), "w"); if (fp) { - fclose(fp); unlink(path); return true; } diff --git a/src/universe.cpp b/src/universe.cpp index 4daa83ef802..1db72f9bb5f 100644 --- a/src/universe.cpp +++ b/src/universe.cpp @@ -16,6 +16,7 @@ #include "error.h" #include "memory.h" +#include "safe_pointers.h" #include @@ -84,7 +85,7 @@ void Universe::reorder(char *style, char *arg) } else if (strcmp(style,"custom") == 0) { if (me == 0) { - FILE *fp = fopen(arg,"r"); + SafeFilePtr fp = fopen(arg,"r"); if (fp == nullptr) error->universe_one(FLERR,fmt::format("Cannot open -reorder file {}: {}", arg, utils::getsyserror())); @@ -122,7 +123,6 @@ void Universe::reorder(char *style, char *arg) "file", me_orig, me_new); uni2orig[me_new] = me_orig; } - fclose(fp); } // bcast uni2org from proc 0 to all other universe procs diff --git a/src/variable.cpp b/src/variable.cpp index 320e22e7321..f72b3173208 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -33,6 +33,7 @@ #include "output.h" #include "random_mars.h" #include "region.h" +#include "safe_pointers.h" #include "thermo.h" #include "timer.h" #include "tokenizer.h" @@ -302,12 +303,10 @@ void Variable::set(int narg, char **arg) which[nvar] = universe->iworld; if (universe->me == 0) { - FILE *fp = fopen("tmp.lammps.variable", "w"); + SafeFilePtr fp = fopen("tmp.lammps.variable", "w"); if (fp == nullptr) error->one(FLERR, "Cannot open temporary file for world counter: " + utils::getsyserror()); fprintf(fp, "%d\n", universe->nworlds); - fclose(fp); - fp = nullptr; } for (int jvar = 0; jvar < nvar; jvar++) @@ -845,7 +844,7 @@ int Variable::next(int narg, char **arg) // and we have to start over. // if the read is short (we need at least one byte) we try reading again. - FILE *fp; + SafeFilePtr fp; char buf[64]; for (int loopmax = 0; loopmax < 100; ++loopmax) { fp = fopen("tmp.lammps.variable.lock","r"); @@ -854,7 +853,6 @@ int Variable::next(int narg, char **arg) buf[0] = buf[1] = '\0'; auto tmp = fread(buf,1,64,fp); (void) tmp; // can be safely ignored, suppress compiler warning in a portable way - fclose(fp); if (strlen(buf) > 0) { nextindex = std::stoi(buf); @@ -872,8 +870,6 @@ int Variable::next(int narg, char **arg) fp = fopen("tmp.lammps.variable.lock","w"); fprintf(fp,"%d\n",nextindex+1); - fclose(fp); - fp = nullptr; (void) rename("tmp.lammps.variable.lock","tmp.lammps.variable"); if (universe->uscreen) fprintf(universe->uscreen, "Increment via next: value %d on partition %d\n", @@ -4949,9 +4945,8 @@ int Variable::special_function(const std::string &word, char *contents, Tree **t if (narg != 1) print_var_error(FLERR,"Invalid is_file() function in variable formula",ivar); - FILE *fp = fopen(args[0],"r"); + SafeFilePtr fp = fopen(args[0],"r"); value = (fp == nullptr) ? 0.0 : 1.0; - if (fp) fclose(fp); // save value in tree or on argstack diff --git a/src/write_coeff.cpp b/src/write_coeff.cpp index 685afc3c398..8a395c2b213 100644 --- a/src/write_coeff.cpp +++ b/src/write_coeff.cpp @@ -22,6 +22,7 @@ #include "force.h" #include "improper.h" #include "pair.h" +#include "safe_pointers.h" #include #include @@ -50,7 +51,7 @@ void WriteCoeff::command(int narg, char **arg) if (comm->me == 0) { char str[BUF_SIZE], coeff[BUF_SIZE]; - FILE *one = fopen(file, "wb+"); + SafeFilePtr one = fopen(file, "wb+"); if (one == nullptr) error->one(FLERR, "Cannot open coeff file {}: {}", file, utils::getsyserror()); @@ -82,7 +83,7 @@ void WriteCoeff::command(int narg, char **arg) } rewind(one); - FILE *two = fopen(arg[0], "w"); + SafeFilePtr two = fopen(arg[0], "w"); if (two == nullptr) error->one(FLERR, "Cannot open coeff file {}: {}", arg[0], utils::getsyserror()); @@ -163,8 +164,6 @@ void WriteCoeff::command(int narg, char **arg) } fputc('\n', two); } - fclose(one); - fclose(two); platform::unlink(file); } delete[] file; From 077f321181f94925f07173282d8c3a606f00b23d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 15 Mar 2026 22:09:41 -0400 Subject: [PATCH 03/12] simplify class. add and integrate doxygen documentation --- doc/doxygen/Doxyfile.in | 1 + doc/src/Developer_utils.rst | 15 ++++++++ src/GRAPHICS/fix_graphics_isosurface.cpp | 2 +- src/safe_pointers.h | 45 ++++++++++++++++++++---- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/doc/doxygen/Doxyfile.in b/doc/doxygen/Doxyfile.in index fadf4eb6898..6a74e0606cc 100644 --- a/doc/doxygen/Doxyfile.in +++ b/doc/doxygen/Doxyfile.in @@ -442,6 +442,7 @@ INPUT = @LAMMPS_SOURCE_DIR@/utils.cpp \ @LAMMPS_SOURCE_DIR@/platform.cpp \ @LAMMPS_SOURCE_DIR@/math_special.h \ @LAMMPS_SOURCE_DIR@/math_special.cpp \ + @LAMMPS_SOURCE_DIR@/safe_pointers.h \ # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/doc/src/Developer_utils.rst b/doc/src/Developer_utils.rst index de5b1dd3349..9d9b241f109 100644 --- a/doc/src/Developer_utils.rst +++ b/doc/src/Developer_utils.rst @@ -482,6 +482,21 @@ A typical code segment would look like this: ---------- +.. _safe-pointer-classes: + +Safe pointer classes +-------------------- + +These are custom classes to support the `Resource acquisition is initialization +(RIAA) `_ +programming idiom in LAMMPS for certain types of pointers. Currently there is: + +.. doxygenclass:: LAMMPS_NS::SafeFilePtr + :project: progguide + :members: + +---------- + .. _file-reader-classes: File reader classes diff --git a/src/GRAPHICS/fix_graphics_isosurface.cpp b/src/GRAPHICS/fix_graphics_isosurface.cpp index 7b11f7e0f2e..bbc16bfd04e 100644 --- a/src/GRAPHICS/fix_graphics_isosurface.cpp +++ b/src/GRAPHICS/fix_graphics_isosurface.cpp @@ -931,7 +931,7 @@ void FixGraphicsIsosurface::end_of_step() if (binary) error->one(FLERR, Error::NOLASTLINE, "Connot use compression with binary output: {}", filename); - fp.set_pclose(true); + fp.set_pclose(); fp = platform::compressed_write(filecurrent); } else if (binary) { fp = fopen(filecurrent, "wb"); diff --git a/src/safe_pointers.h b/src/safe_pointers.h index 363b513a9f2..a4643216502 100644 --- a/src/safe_pointers.h +++ b/src/safe_pointers.h @@ -20,20 +20,53 @@ namespace LAMMPS_NS { -/** Class to automatically close a FILE pointer when a class instance goes out of scope. +/** Class to automatically close a FILE pointer when it goes out of scope \verbatim embed:rst -Drop in replacement for ``FILE *``. Use as ``SafeFilePtr fp;`` instead of -``FILE *fp = nullptr;`` and there is no more need to explicitly call -``fclose(fp)`` or ``pclose(fp)``. +This is a drop-in replacement for declaring a ``FILE *`` variable and can +be passed to functions or used in logical expressions the same way. This +is particularly useful when a code block will throw an exception, or has +to close and re-open a file and similar. It helps to simplify code and +reduces the risk of memory and file descriptor leaks. + +Below are some usage examples: + +.. code-block:: c++ + + // Replace: + FILE *fp = nullptr; + // With: + SafeFilePtr fp; + + // You can use "fp" as usual: + fp = fopen("some.file","r"); + // a second assignment will automatically close the opened file + fp = fopen("other.file", "r"); + + // There also is a custom constructor available as a shortcut + SafeFilePtr fp(fopen("some.file", "r"); + + // You can indicate that a file was opened with popen() to call pclose() instead of fclose() + SafeFilePtr fp; + if (platform::has_compress_extension(filename)) { + fp.set_pclose(); + fp = platform::compressed_write(filename); + } else { + fp = fopen(filename, "w"); + } + if (!fp) error->one(FLERR, "Failed to open file {}: {}", filename, utils::getsyserror()); + + // reading or writing works without needing to change the source code + fputs("write text to file\n", fp); + char buffer[100]; + utils::sfgets(FILE, buffer, 100, fp, filename, error); \endverbatim */ class SafeFilePtr { public: SafeFilePtr() : fp(nullptr), use_pclose(false) {}; - SafeFilePtr(bool _use_pclose) : fp(nullptr), use_pclose(_use_pclose) {}; SafeFilePtr(FILE *_fp, bool _use_pclose = false) : fp(_fp), use_pclose(_use_pclose) {}; SafeFilePtr(const SafeFilePtr &) = delete; @@ -61,7 +94,7 @@ class SafeFilePtr { fp = _fp; return *this; } - void set_pclose(bool _use_pclose) { use_pclose = _use_pclose; } + void set_pclose() { use_pclose = true; } operator FILE *() const { return fp; } private: From bc752dd8d3debf0112cad8ae2d7d6caa5d74586f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 15 Mar 2026 22:22:36 -0400 Subject: [PATCH 04/12] add local TOC and have consistent separator lines --- doc/src/Developer_utils.rst | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/doc/src/Developer_utils.rst b/doc/src/Developer_utils.rst index 9d9b241f109..c39e6035ea7 100644 --- a/doc/src/Developer_utils.rst +++ b/doc/src/Developer_utils.rst @@ -11,6 +11,11 @@ reduces redundant implementations and encourages consistent behavior and thus has some overlap with the :doc:`"platform" sub-namespace `. +.. contents:: + :local: + +---------- + I/O with status check and similar functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,6 +114,7 @@ strings for compliance without conversion. .. doxygenfunction:: logical(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) :project: progguide +---------- String processing ^^^^^^^^^^^^^^^^^ @@ -193,6 +199,8 @@ and parsing files or arguments. .. doxygenfunction:: is_type :project: progguide +---------- + Potential file functions ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -214,6 +222,8 @@ Potential file functions .. doxygenfunction:: open_potential(const std::string &name, LAMMPS *lmp, int *auto_convert) :project: progguide +---------- + Argument processing ^^^^^^^^^^^^^^^^^^^ @@ -232,6 +242,8 @@ Argument processing .. doxygenfunction:: expand_type :project: progguide +---------- + Convenience functions ^^^^^^^^^^^^^^^^^^^^^ @@ -274,6 +286,8 @@ Convenience functions .. doxygenfunction:: current_date :project: progguide +---------- + Customized standard functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -283,7 +297,7 @@ Customized standard functions .. doxygenfunction:: merge_sort :project: progguide ---------------------------- +---------- Special Math functions ---------------------- @@ -321,7 +335,7 @@ mathematical functions for a variety of applications. .. doxygenfunction:: powsinxx :project: progguide ---------------------------- +---------- Tokenizer classes ----------------- @@ -439,7 +453,7 @@ This code example should produce the following output: Argument parsing classes ---------------------------- +------------------------ The purpose of argument parsing classes it to simplify and unify how arguments of commands in LAMMPS are parsed and to make abstractions of @@ -813,7 +827,7 @@ Tohoku University (under MIT license) .. doxygenfunction:: MathEigen::jacobi3(double const mat[3][3], double *eval, double evec[3][3], int sort) :project: progguide ---------------------------- +---------- .. _communication_buffer_coding_with_ubuf: @@ -831,7 +845,7 @@ union. It is used in the various "pack" and "unpack" functions in the LAMMPS classes to store and retrieve integers that may be 64-bit from the communication buffers. ---------------------------- +---------- .. doxygenunion:: LAMMPS_NS::ubuf :project: progguide From 22ca1e439015678f314a2a6ac9bbd8023f105fce Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 15 Mar 2026 22:34:44 -0400 Subject: [PATCH 05/12] use platform portable pclose() wrapper --- src/safe_pointers.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/safe_pointers.h b/src/safe_pointers.h index a4643216502..dff26646064 100644 --- a/src/safe_pointers.h +++ b/src/safe_pointers.h @@ -16,6 +16,8 @@ // collection of smart pointers for specific purposes +#include "platform.h" + #include namespace LAMMPS_NS { @@ -77,7 +79,7 @@ class SafeFilePtr { { if (fp) { if (use_pclose) - pclose(fp); + platform::pclose(fp); else fclose(fp); } @@ -87,7 +89,7 @@ class SafeFilePtr { { if (fp && (fp != _fp)) { if (use_pclose) - pclose(fp); + platform::pclose(fp); else fclose(fp); } From f7a0b3d41b51868ab3f246298b18de7e87f99756 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 15 Mar 2026 22:45:06 -0400 Subject: [PATCH 06/12] split into two files, so we don't have to pull in platform.h in the header --- src/safe_pointers.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ src/safe_pointers.h | 24 ++---------------------- 2 files changed, 44 insertions(+), 22 deletions(-) create mode 100644 src/safe_pointers.cpp diff --git a/src/safe_pointers.cpp b/src/safe_pointers.cpp new file mode 100644 index 00000000000..7952ddabba8 --- /dev/null +++ b/src/safe_pointers.cpp @@ -0,0 +1,42 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + LAMMPS development team: developers@lammps.org + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +// collection of smart pointers for specific purposes + +#include "safe_pointers.h" + +#include "platform.h" + +using namespace LAMMPS_NS; + +SafeFilePtr::~SafeFilePtr() +{ + if (fp) { + if (use_pclose) + platform::pclose(fp); + else + fclose(fp); + } +} + +SafeFilePtr &SafeFilePtr::operator=(FILE *_fp) +{ + if (fp && (fp != _fp)) { + if (use_pclose) + platform::pclose(fp); + else + fclose(fp); + } + fp = _fp; + return *this; +} diff --git a/src/safe_pointers.h b/src/safe_pointers.h index dff26646064..327ab70f635 100644 --- a/src/safe_pointers.h +++ b/src/safe_pointers.h @@ -16,8 +16,6 @@ // collection of smart pointers for specific purposes -#include "platform.h" - #include namespace LAMMPS_NS { @@ -75,27 +73,9 @@ class SafeFilePtr { SafeFilePtr(SafeFilePtr &&o) noexcept : fp(o.fp), use_pclose(o.use_pclose) { o.fp = nullptr; } SafeFilePtr &operator=(const SafeFilePtr &) = delete; - ~SafeFilePtr() - { - if (fp) { - if (use_pclose) - platform::pclose(fp); - else - fclose(fp); - } - } + ~SafeFilePtr(); - SafeFilePtr &operator=(FILE *_fp) - { - if (fp && (fp != _fp)) { - if (use_pclose) - platform::pclose(fp); - else - fclose(fp); - } - fp = _fp; - return *this; - } + SafeFilePtr &operator=(FILE *_fp); void set_pclose() { use_pclose = true; } operator FILE *() const { return fp; } From d826416b9ca17ef19c705a27af40d29cbca4308c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 16 Mar 2026 07:22:15 -0400 Subject: [PATCH 07/12] convert some commands with FILE * pointer as class member to use SafeFilePtr --- src/read_restart.cpp | 17 ++--------------- src/read_restart.h | 3 ++- src/variable.cpp | 6 ------ src/variable.h | 3 ++- src/write_data.cpp | 5 +---- src/write_data.h | 3 ++- src/write_restart.cpp | 17 ++++++++++------- src/write_restart.h | 3 ++- 8 files changed, 21 insertions(+), 36 deletions(-) diff --git a/src/read_restart.cpp b/src/read_restart.cpp index 19531a421f4..d074765e8b2 100644 --- a/src/read_restart.cpp +++ b/src/read_restart.cpp @@ -165,8 +165,7 @@ void ReadRestart::command(int narg, char **arg) // close header file if in multiproc mode if (multiproc && me == 0) { - fclose(fp); - fp = nullptr; + fp = nullptr; // implicitly closes the file } // read per-proc info @@ -230,11 +229,6 @@ void ReadRestart::command(int narg, char **arg) } else m += static_cast (buf[m]); } } - - if (me == 0) { - fclose(fp); - fp = nullptr; - } } // input of multiple native files with procs <= files @@ -272,9 +266,6 @@ void ReadRestart::command(int narg, char **arg) m = 0; while (m < n) m += avec->unpack_restart(&buf[m]); } - - fclose(fp); - fp = nullptr; } } @@ -367,10 +358,6 @@ void ReadRestart::command(int narg, char **arg) } } - if (filereader && fp != nullptr) { - fclose(fp); - fp = nullptr; - } MPI_Comm_free(&clustercomm); } @@ -379,7 +366,7 @@ void ReadRestart::command(int narg, char **arg) delete[] file; memory->destroy(buf); - // for multiproc or MPI-IO files: + // for multiproc files: // perform irregular comm to migrate atoms to correct procs if (multiproc) { diff --git a/src/read_restart.h b/src/read_restart.h index ffc4d00e916..7a3a82733e5 100644 --- a/src/read_restart.h +++ b/src/read_restart.h @@ -21,6 +21,7 @@ CommandStyle(read_restart,ReadRestart); #define LMP_READ_RESTART_H #include "command.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -31,7 +32,7 @@ class ReadRestart : public Command { private: int me, nprocs; - FILE *fp; + SafeFilePtr fp; int multiproc; // 0 = restart file is a single file // 1 = restart file is parallel (multiple files) diff --git a/src/variable.cpp b/src/variable.cpp index f72b3173208..44efd52ecd3 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -5705,7 +5705,6 @@ VarReader::VarReader(LAMMPS *lmp, char *name, char *file, int flag) : { me = comm->me; style = flag; - fp = nullptr; if (me == 0) { fp = fopen(file,"r"); @@ -5737,11 +5736,6 @@ VarReader::VarReader(LAMMPS *lmp, char *name, char *file, int flag) : VarReader::~VarReader() { - if (me == 0) { - fclose(fp); - fp = nullptr; - } - // check modify in case all fixes have already been deleted if (fixstore) { diff --git a/src/variable.h b/src/variable.h index fd815d82417..139b4ff9f03 100644 --- a/src/variable.h +++ b/src/variable.h @@ -15,6 +15,7 @@ #define LMP_VARIABLE_H #include "pointers.h" +#include "safe_pointers.h" namespace LAMMPS_NS { class Region; @@ -176,7 +177,7 @@ class VarReader : protected Pointers { private: int me, style; - FILE *fp; + SafeFilePtr fp; char *buffer; }; diff --git a/src/write_data.cpp b/src/write_data.cpp index 9f03d876f81..a9f3066a9a2 100644 --- a/src/write_data.cpp +++ b/src/write_data.cpp @@ -204,6 +204,7 @@ void WriteData::write(const std::string &file) if (comm->me == 0) { if (platform::has_compress_extension(file)) { + fp.set_pclose(); fp = platform::compressed_write(file); } else { fp = fopen(file.c_str(), "w"); @@ -266,10 +267,6 @@ void WriteData::write(const std::string &file) // restore internal per-atom data that was rotated if (domain->triclinic_general) atom->avec->write_data_restore_restricted(); - - // close data file - - if (comm->me == 0) fclose(fp); } /* ---------------------------------------------------------------------- diff --git a/src/write_data.h b/src/write_data.h index b98fd6594df..ac5525dff0c 100644 --- a/src/write_data.h +++ b/src/write_data.h @@ -21,6 +21,7 @@ CommandStyle(write_data,WriteData); #define LMP_WRITE_DATA_H #include "command.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -37,7 +38,7 @@ class WriteData : public Command { int triclinic_general; int lmapflag; int noinitflag; - FILE *fp; + SafeFilePtr fp; bigint nbonds_local, nbonds; bigint nangles_local, nangles; bigint ndihedrals_local, ndihedrals; diff --git a/src/write_restart.cpp b/src/write_restart.cpp index 7614ba6acd5..39b68f13d6d 100644 --- a/src/write_restart.cpp +++ b/src/write_restart.cpp @@ -49,7 +49,6 @@ WriteRestart::WriteRestart(LAMMPS *lmp) : Command(lmp) MPI_Comm_size(world,&nprocs); multiproc = 0; noinit = 0; - fp = nullptr; } /* ---------------------------------------------------------------------- @@ -268,8 +267,7 @@ void WriteRestart::write(const std::string &file) if (me == 0 && fp) { magic_string(); if (ferror(fp)) io_error = 1; - fclose(fp); - fp = nullptr; + fp = nullptr; // implicitly closes file } std::string multiname = file; @@ -283,6 +281,12 @@ void WriteRestart::write(const std::string &file) } } + // check for I/O error status + + int io_all = 0; + MPI_Allreduce(&io_error,&io_all,1,MPI_INT,MPI_MAX,world); + if (io_all) error->all(FLERR,"I/O error while writing restart"); + // pack my atom data into buf AtomVec *avec = atom->avec; @@ -361,17 +365,16 @@ void WriteRestart::write(const std::string &file) } magic_string(); if (ferror(fp)) io_error = 1; - fclose(fp); - fp = nullptr; + fp = nullptr; // implicitly closes file } else { MPI_Recv(&tmp,0,MPI_INT,fileproc,0,world,MPI_STATUS_IGNORE); MPI_Rsend(buf,send_size,MPI_DOUBLE,fileproc,0,world); } - // check for I/O error status + // check again for I/O error status - int io_all = 0; + io_all = 0; MPI_Allreduce(&io_error,&io_all,1,MPI_INT,MPI_MAX,world); if (io_all) error->all(FLERR,"I/O error while writing restart"); diff --git a/src/write_restart.h b/src/write_restart.h index 1dcb003a4b3..3595617259c 100644 --- a/src/write_restart.h +++ b/src/write_restart.h @@ -21,6 +21,7 @@ CommandStyle(write_restart,WriteRestart); #define LMP_WRITE_RESTART_H #include "command.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -33,7 +34,7 @@ class WriteRestart : public Command { private: int me, nprocs; - FILE *fp; + SafeFilePtr fp; bigint natoms; // natoms (sum of nlocal) to write into file int noinit; From d2ad9e50a018fed1d75cfcae91d609c8dd3a3c9b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 16 Mar 2026 08:16:24 -0400 Subject: [PATCH 08/12] convert more classes to use SafeFilePtr --- src/fix_print.cpp | 6 +- src/fix_print.h | 3 +- src/molecule.cpp | 190 +++++++++++++++++++++++----------------------- src/molecule.h | 3 +- src/read_data.cpp | 20 +---- src/read_data.h | 5 +- src/reader.cpp | 12 +-- src/reader.h | 6 +- 8 files changed, 109 insertions(+), 136 deletions(-) diff --git a/src/fix_print.cpp b/src/fix_print.cpp index 1d60addfa40..6b74f0dfcfd 100644 --- a/src/fix_print.cpp +++ b/src/fix_print.cpp @@ -29,8 +29,7 @@ using namespace FixConst; /* ---------------------------------------------------------------------- */ FixPrint::FixPrint(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), fp(nullptr), text(nullptr), copy(nullptr), work(nullptr), - var_print(nullptr) + Fix(lmp, narg, arg), text(nullptr), copy(nullptr), work(nullptr), var_print(nullptr) { if (narg < 5) utils::missing_cmd_args(FLERR, "fix print", error); if (utils::strmatch(arg[3], "^v_")) { @@ -49,7 +48,6 @@ FixPrint::FixPrint(LAMMPS *lmp, int narg, char **arg) : // parse optional args - fp = nullptr; screenflag = 1; char *title = nullptr; @@ -101,8 +99,6 @@ FixPrint::~FixPrint() delete[] var_print; memory->sfree(copy); memory->sfree(work); - - if (fp && (comm->me == 0)) fclose(fp); } /* ---------------------------------------------------------------------- */ diff --git a/src/fix_print.h b/src/fix_print.h index 9e699e22ba2..870724a68ff 100644 --- a/src/fix_print.h +++ b/src/fix_print.h @@ -21,6 +21,7 @@ FixStyle(print,FixPrint); #define LMP_FIX_PRINT_H #include "fix.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -35,7 +36,7 @@ class FixPrint : public Fix { private: int screenflag; - FILE *fp; + SafeFilePtr fp; char *text, *copy, *work; int maxcopy, maxwork; char *var_print; diff --git a/src/molecule.cpp b/src/molecule.cpp index 5206f0ee7ce..d776ba8bf8c 100644 --- a/src/molecule.cpp +++ b/src/molecule.cpp @@ -56,8 +56,7 @@ Molecule::Molecule(LAMMPS *lmp) : improper_atom2(nullptr), improper_atom3(nullptr), improper_atom4(nullptr), nspecial(nullptr), special(nullptr), shake_flag(nullptr), shake_atom(nullptr), shake_type(nullptr), avec_body(nullptr), ibodyparams(nullptr), dbodyparams(nullptr), fragmentmask(nullptr), - dx(nullptr), dxcom(nullptr), dxbody(nullptr), quat_external(nullptr), fp(nullptr), - count(nullptr) + dx(nullptr), dxcom(nullptr), dxbody(nullptr), quat_external(nullptr), count(nullptr) { // parse args until reach unknown arg (next file) @@ -137,14 +136,10 @@ void Molecule::command(int narg, char **arg, int &index) iarg += 2; } else if (strcmp(arg[iarg], "check_labels") == 0) { if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "check_labels", error); - if (strchr(arg[iarg + 1], 'b')) - check_which_labels[0] = 1; - if (strchr(arg[iarg + 1], 'a')) - check_which_labels[1] = 1; - if (strchr(arg[iarg + 1], 'd')) - check_which_labels[2] = 1; - if (strchr(arg[iarg + 1], 'i')) - check_which_labels[3] = 1; + if (strchr(arg[iarg + 1], 'b')) check_which_labels[0] = 1; + if (strchr(arg[iarg + 1], 'a')) check_which_labels[1] = 1; + if (strchr(arg[iarg + 1], 'd')) check_which_labels[2] = 1; + if (strchr(arg[iarg + 1], 'i')) check_which_labels[3] = 1; iarg += 2; } else break; @@ -187,9 +182,7 @@ void Molecule::command(int narg, char **arg, int &index) moldata = json::parse(fp); jsondata = json::to_ubjson(moldata); jsondata_size = jsondata.size(); - fclose(fp); } catch (std::exception &e) { - fclose(fp); error->one(FLERR, fileiarg, "Error parsing JSON file {}: {}", filename, e.what()); } } @@ -231,7 +224,6 @@ void Molecule::command(int narg, char **arg, int &index) if (comm->me == 0) rewind(fp); Molecule::read(1); - if (comm->me == 0) fclose(fp); } if (comm->me == 0) Molecule::check_labels(); Molecule::stats(); @@ -1952,8 +1944,8 @@ json Molecule::to_json() const for (int j = 0; j < num_bond[i]; j++) { if (has_newton_bond || (i + 1 < bond_atom[i][j])) { if (has_typelabels) { - moldata["bonds"]["data"][idx] = {atom->lmap->find_label(bond_type[i][j], Atom::BOND), i + 1, - bond_atom[i][j]}; + moldata["bonds"]["data"][idx] = {atom->lmap->find_label(bond_type[i][j], Atom::BOND), + i + 1, bond_atom[i][j]}; } else { moldata["bonds"]["data"][idx] = {bond_type[i][j], i + 1, bond_atom[i][j]}; } @@ -4366,78 +4358,78 @@ void Molecule::stats() print molecule file. may only be called from MPI rank 0 ------------------------------------------------------------------------- */ -void Molecule::print(FILE *fp) +void Molecule::print(FILE *out) { - utils::print(fp, " {} atoms\n", natoms); - if (nbonds) utils::print(fp, " {} bonds\n", nbonds); - if (nangles) utils::print(fp, " {} angles\n", nangles); - if (ndihedrals) utils::print(fp, " {} dihedrals\n", ndihedrals); - if (nimpropers) utils::print(fp, " {} impropers\n", nimpropers); - if (nfragments) utils::print(fp, " {} fragments\n", nfragments); - if (massflag_user) utils::print(fp, " {} mass\n", masstotal); - if (bodyflag) utils::print(fp, " {} {} body\n", nibody, ndbody); - if (comflag_user) utils::print(fp, " {} {} {} com\n", com[0], com[1], com[2]); + utils::print(out, " {} atoms\n", natoms); + if (nbonds) utils::print(out, " {} bonds\n", nbonds); + if (nangles) utils::print(out, " {} angles\n", nangles); + if (ndihedrals) utils::print(out, " {} dihedrals\n", ndihedrals); + if (nimpropers) utils::print(out, " {} impropers\n", nimpropers); + if (nfragments) utils::print(out, " {} fragments\n", nfragments); + if (massflag_user) utils::print(out, " {} mass\n", masstotal); + if (bodyflag) utils::print(out, " {} {} body\n", nibody, ndbody); + if (comflag_user) utils::print(out, " {} {} {} com\n", com[0], com[1], com[2]); if (inertiaflag_user) - utils::print(fp, " {} {} {} {} {} {} inertia\n", itensor[0], itensor[1], itensor[2], + utils::print(out, " {} {} {} {} {} {} inertia\n", itensor[0], itensor[1], itensor[2], itensor[3], itensor[4], itensor[5]); if (xflag) { - fputs("\nCoords\n\n", fp); + fputs("\nCoords\n\n", out); for (int i = 0; i < natoms; i++) - utils::print(fp, " {} {} {} {}\n", i + 1, x[i][0], x[i][1], x[i][2]); + utils::print(out, " {} {} {} {}\n", i + 1, x[i][0], x[i][1], x[i][2]); } if (typeflag) { - fputs("\nTypes\n\n", fp); + fputs("\nTypes\n\n", out); if (atom->labelmapflag && atom->lmap->is_complete(Atom::ATOM)) { for (int i = 0; i < natoms; i++) - utils::print(fp, " {} {}\n", i + 1, atom->lmap->find_label(type[i], Atom::ATOM)); + utils::print(out, " {} {}\n", i + 1, atom->lmap->find_label(type[i], Atom::ATOM)); } else { - for (int i = 0; i < natoms; i++) utils::print(fp, " {} {}\n", i + 1, type[i]); + for (int i = 0; i < natoms; i++) utils::print(out, " {} {}\n", i + 1, type[i]); } } if (moleculeflag) { - fputs("\nMolecules\n\n", fp); - for (int i = 0; i < natoms; i++) utils::print(fp, " {} {}\n", i + 1, molecule[i]); + fputs("\nMolecules\n\n", out); + for (int i = 0; i < natoms; i++) utils::print(out, " {} {}\n", i + 1, molecule[i]); } if (fragmentflag) { - fputs("\nFragments\n\n", fp); + fputs("\nFragments\n\n", out); for (int i = 0; i < nfragments; i++) { - utils::print(fp, " {} ", fragmentnames[i]); + utils::print(out, " {} ", fragmentnames[i]); for (int j = 0; j < natoms; j++) { - if (fragmentmask[i][j]) utils::print(fp, " {}", j + 1); + if (fragmentmask[i][j]) utils::print(out, " {}", j + 1); } - fputs("\n", fp); + fputs("\n", out); } } if (qflag) { - fputs("\nCharges\n\n", fp); - for (int i = 0; i < natoms; i++) utils::print(fp, " {} {}\n", i + 1, q[i]); + fputs("\nCharges\n\n", out); + for (int i = 0; i < natoms; i++) utils::print(out, " {} {}\n", i + 1, q[i]); } if (radiusflag && !bodyflag) { - fputs("\nDiameters\n\n", fp); - for (int i = 0; i < natoms; i++) utils::print(fp, " {} {}\n", i + 1, 2.0 * radius[i]); + fputs("\nDiameters\n\n", out); + for (int i = 0; i < natoms; i++) utils::print(out, " {} {}\n", i + 1, 2.0 * radius[i]); } if (muflag) { - fputs("\nDipoles\n\n", fp); + fputs("\nDipoles\n\n", out); for (int i = 0; i < natoms; i++) - utils::print(fp, " {} {} {} {}\n", i + 1, mu[i][0], mu[i][1], mu[i][2]); + utils::print(out, " {} {} {} {}\n", i + 1, mu[i][0], mu[i][1], mu[i][2]); } if (rmassflag) { - fputs("\nMasses\n\n", fp); - for (int i = 0; i < natoms; i++) utils::print(fp, " {} {}\n", i + 1, rmass[i]); + fputs("\nMasses\n\n", out); + for (int i = 0; i < natoms; i++) utils::print(out, " {} {}\n", i + 1, rmass[i]); } bool has_newton_bond = force->newton_bond > 0; if (bondflag) { - fputs("\nBonds\n\n", fp); + fputs("\nBonds\n\n", out); int idx = 0; bool has_typelabels = (atom->labelmapflag != 0) && atom->lmap->is_complete(Atom::BOND); @@ -4446,18 +4438,18 @@ void Molecule::print(FILE *fp) if (has_newton_bond || (i + 1 < bond_atom[i][j])) { ++idx; if (has_typelabels) { - utils::print(fp, " {} {}", idx, atom->lmap->find_label(bond_type[i][j], Atom::BOND)); + utils::print(out, " {} {}", idx, atom->lmap->find_label(bond_type[i][j], Atom::BOND)); } else { - utils::print(fp, " {} {}", idx, bond_type[i][j]); + utils::print(out, " {} {}", idx, bond_type[i][j]); } - utils::print(fp, " {} {}\n", i + 1, bond_atom[i][j]); + utils::print(out, " {} {}\n", i + 1, bond_atom[i][j]); } } } } if (angleflag) { - fputs("\nAngles\n\n", fp); + fputs("\nAngles\n\n", out); int idx = 0; bool has_typelabels = (atom->labelmapflag != 0) && atom->lmap->is_complete(Atom::ANGLE); for (int i = 0; i < natoms; i++) { @@ -4465,18 +4457,19 @@ void Molecule::print(FILE *fp) if (has_newton_bond || (i + 1 == angle_atom2[i][j])) { ++idx; if (has_typelabels) { - utils::print(fp, " {} {}", idx, atom->lmap->find_label(angle_type[i][j], Atom::ANGLE)); + utils::print(out, " {} {}", idx, + atom->lmap->find_label(angle_type[i][j], Atom::ANGLE)); } else { - utils::print(fp, " {} {}", idx, angle_type[i][j]); + utils::print(out, " {} {}", idx, angle_type[i][j]); } - utils::print(fp, " {} {} {}\n", angle_atom1[i][j], angle_atom2[i][j], angle_atom3[i][j]); + utils::print(out, " {} {} {}\n", angle_atom1[i][j], angle_atom2[i][j], angle_atom3[i][j]); } } } } if (dihedralflag) { - fputs("\nDihedrals\n\n", fp); + fputs("\nDihedrals\n\n", out); int idx = 0; bool has_typelabels = (atom->labelmapflag != 0) && atom->lmap->is_complete(Atom::DIHEDRAL); for (int i = 0; i < natoms; i++) { @@ -4484,11 +4477,12 @@ void Molecule::print(FILE *fp) if (has_newton_bond || (i + 1 == dihedral_atom2[i][j])) { ++idx; if (has_typelabels) { - utils::print(fp, " {} {}", idx, atom->lmap->find_label(dihedral_type[i][j], Atom::DIHEDRAL)); + utils::print(out, " {} {}", idx, + atom->lmap->find_label(dihedral_type[i][j], Atom::DIHEDRAL)); } else { - utils::print(fp, " {} {}", idx, dihedral_type[i][j]); + utils::print(out, " {} {}", idx, dihedral_type[i][j]); } - utils::print(fp, " {} {} {} {}\n", dihedral_atom1[i][j], dihedral_atom2[i][j], + utils::print(out, " {} {} {} {}\n", dihedral_atom1[i][j], dihedral_atom2[i][j], dihedral_atom3[i][j], dihedral_atom4[i][j]); } } @@ -4496,7 +4490,7 @@ void Molecule::print(FILE *fp) } if (improperflag) { - fputs("\nImpropers\n\n", fp); + fputs("\nImpropers\n\n", out); int idx = 0; bool has_typelabels = (atom->labelmapflag != 0) && atom->lmap->is_complete(Atom::IMPROPER); for (int i = 0; i < natoms; i++) { @@ -4504,11 +4498,12 @@ void Molecule::print(FILE *fp) if (has_newton_bond || (i + 1 == improper_atom2[i][j])) { ++idx; if (has_typelabels) { - utils::print(fp, " {} {}", idx, atom->lmap->find_label(improper_type[i][j], Atom::IMPROPER)); + utils::print(out, " {} {}", idx, + atom->lmap->find_label(improper_type[i][j], Atom::IMPROPER)); } else { - utils::print(fp, " {} {}", idx, improper_type[i][j]); + utils::print(out, " {} {}", idx, improper_type[i][j]); } - utils::print(fp, " {} {} {} {}\n", improper_atom1[i][j], improper_atom2[i][j], + utils::print(out, " {} {} {} {}\n", improper_atom1[i][j], improper_atom2[i][j], improper_atom3[i][j], improper_atom4[i][j]); } } @@ -4516,100 +4511,101 @@ void Molecule::print(FILE *fp) } if (specialflag_user) { - fputs("\nSpecial Bond Counts\n\n", fp); + fputs("\nSpecial Bond Counts\n\n", out); for (int i = 0; i < natoms; i++) { - utils::print(fp, " {} {} {} {}\n", i + 1, nspecial[i][0], nspecial[i][1] - nspecial[i][0], + utils::print(out, " {} {} {} {}\n", i + 1, nspecial[i][0], nspecial[i][1] - nspecial[i][0], nspecial[i][2] - nspecial[i][1]); } - fputs("\nSpecial Bonds\n\n", fp); + fputs("\nSpecial Bonds\n\n", out); for (int i = 0; i < natoms; i++) { - utils::print(fp, " {} ", i + 1); - for (int j = 0; j < nspecial[i][2]; j++) utils::print(fp, " {}", special[i][j]); - utils::print(fp, "\n"); + utils::print(out, " {} ", i + 1); + for (int j = 0; j < nspecial[i][2]; j++) utils::print(out, " {}", special[i][j]); + utils::print(out, "\n"); } } if (shakeflag) { - fputs("\nShake Flags\n\n", fp); - for (int i = 0; i < natoms; i++) { utils::print(fp, " {} {}\n", i + 1, shake_flag[i]); } + fputs("\nShake Flags\n\n", out); + for (int i = 0; i < natoms; i++) utils::print(out, " {} {}\n", i + 1, shake_flag[i]); - fputs("\nShake Atoms\n\n", fp); + fputs("\nShake Atoms\n\n", out); for (int i = 0; i < natoms; i++) { - utils::print(fp, " {} ", i + 1); + utils::print(out, " {} ", i + 1); switch (shake_flag[i]) { case 1: - utils::print(fp, " {} {} {}\n", shake_atom[i][0], shake_atom[i][1], shake_atom[i][2]); + utils::print(out, " {} {} {}\n", shake_atom[i][0], shake_atom[i][1], shake_atom[i][2]); break; case 2: - utils::print(fp, " {} {}\n", shake_atom[i][0], shake_atom[i][1]); + utils::print(out, " {} {}\n", shake_atom[i][0], shake_atom[i][1]); break; case 3: - utils::print(fp, " {} {} {}\n", shake_atom[i][0], shake_atom[i][1], shake_atom[i][2]); + utils::print(out, " {} {} {}\n", shake_atom[i][0], shake_atom[i][1], shake_atom[i][2]); break; case 4: - utils::print(fp, " {} {} {} {}\n", shake_atom[i][0], shake_atom[i][1], shake_atom[i][2], + utils::print(out, " {} {} {} {}\n", shake_atom[i][0], shake_atom[i][1], shake_atom[i][2], shake_atom[i][3]); break; case 0: - fputs("\n", fp); + fputs("\n", out); break; } } - fputs("\nShake Bond Types\n\n", fp); + fputs("\nShake Bond Types\n\n", out); for (int i = 0; i < natoms; i++) { bool has_typelabels = (atom->labelmapflag != 0) && atom->lmap->is_complete(Atom::BOND); - utils::print(fp, " {} ", i + 1); + utils::print(out, " {} ", i + 1); switch (shake_flag[i]) { case 1: has_typelabels = has_typelabels && atom->lmap->is_complete(Atom::ANGLE); if (has_typelabels) { - utils::print(fp, " {} {} {}\n", atom->lmap->find_label(shake_type[i][0], Atom::BOND), + utils::print(out, " {} {} {}\n", atom->lmap->find_label(shake_type[i][0], Atom::BOND), atom->lmap->find_label(shake_type[i][1], Atom::BOND), atom->lmap->find_label(shake_type[i][2], Atom::ANGLE)); } else { - utils::print(fp, " {} {} {}\n", shake_type[i][0], shake_type[i][1], shake_type[i][2]); + utils::print(out, " {} {} {}\n", shake_type[i][0], shake_type[i][1], shake_type[i][2]); } break; case 2: if (has_typelabels) { - utils::print(fp, " {} {}\n", atom->lmap->find_label(shake_type[i][0], Atom::BOND), + utils::print(out, " {} {}\n", atom->lmap->find_label(shake_type[i][0], Atom::BOND), atom->lmap->find_label(shake_type[i][1], Atom::BOND)); } else { - utils::print(fp, " {} {}\n", shake_type[i][0], shake_type[i][1]); + utils::print(out, " {} {}\n", shake_type[i][0], shake_type[i][1]); } break; case 3: if (has_typelabels) { - utils::print(fp, " {} {} {}\n", atom->lmap->find_label(shake_type[i][0], Atom::BOND), + utils::print(out, " {} {} {}\n", atom->lmap->find_label(shake_type[i][0], Atom::BOND), atom->lmap->find_label(shake_type[i][1], Atom::BOND), atom->lmap->find_label(shake_type[i][2], Atom::BOND)); } else { - utils::print(fp, " {} {} {}\n", shake_type[i][0], shake_type[i][1], shake_type[i][2]); + utils::print(out, " {} {} {}\n", shake_type[i][0], shake_type[i][1], shake_type[i][2]); } break; case 4: if (has_typelabels) { - utils::print(fp, " {} {} {} {}\n", atom->lmap->find_label(shake_type[i][0], Atom::BOND), + utils::print(out, " {} {} {} {}\n", + atom->lmap->find_label(shake_type[i][0], Atom::BOND), atom->lmap->find_label(shake_type[i][1], Atom::BOND), atom->lmap->find_label(shake_type[i][2], Atom::BOND), atom->lmap->find_label(shake_type[i][3], Atom::BOND)); } else { - utils::print(fp, " {} {} {} {}\n", shake_type[i][0], shake_type[i][1], shake_type[i][2], - shake_type[i][3]); + utils::print(out, " {} {} {} {}\n", shake_type[i][0], shake_type[i][1], + shake_type[i][2], shake_type[i][3]); } break; case 0: - fputs("\n", fp); + fputs("\n", out); break; } } @@ -4618,35 +4614,35 @@ void Molecule::print(FILE *fp) if (bodyflag) { auto *avec = dynamic_cast(atom->style_match("body")); if (avec) { - fputs("\nBody Integers\n\n", fp); + fputs("\nBody Integers\n\n", out); if ((strcmp(avec->bptr->style, "nparticle") == 0) || (strcmp(avec->bptr->style, "rounded/polygon") == 0)) { - utils::print(fp, " {}\n", ibodyparams[0]); + utils::print(out, " {}\n", ibodyparams[0]); } if (strcmp(avec->bptr->style, "rounded/polyhedron") == 0) { - utils::print(fp, " {} {} {}\n", ibodyparams[0], ibodyparams[1], ibodyparams[2]); + utils::print(out, " {} {} {}\n", ibodyparams[0], ibodyparams[1], ibodyparams[2]); } - fputs("\nBody Doubles\n\n", fp); - utils::print(fp, " {} {} {} {} {} {}\n", dbodyparams[0], dbodyparams[1], dbodyparams[2], + fputs("\nBody Doubles\n\n", out); + utils::print(out, " {} {} {} {} {} {}\n", dbodyparams[0], dbodyparams[1], dbodyparams[2], dbodyparams[3], dbodyparams[4], dbodyparams[5]); int idx = 6; for (int i = 0; i < ibodyparams[0]; ++i) { - utils::print(fp, " {} {} {}\n", dbodyparams[idx], dbodyparams[idx + 1], + utils::print(out, " {} {} {}\n", dbodyparams[idx], dbodyparams[idx + 1], dbodyparams[idx + 2]); idx += 3; } if (strcmp(avec->bptr->style, "rounded/polyhedron") == 0) { for (int i = 0; i < ibodyparams[1]; ++i) { - utils::print(fp, " {} {}\n", dbodyparams[idx], dbodyparams[idx + 1]); + utils::print(out, " {} {}\n", dbodyparams[idx], dbodyparams[idx + 1]); idx += 2; } for (int i = 0; i < ibodyparams[2]; ++i) { - utils::print(fp, " {} {} {} {}\n", dbodyparams[idx], dbodyparams[idx + 1], + utils::print(out, " {} {} {} {}\n", dbodyparams[idx], dbodyparams[idx + 1], dbodyparams[idx + 2], dbodyparams[idx + 3]); idx += 4; } } - utils::print(fp, " {}\n", dbodyparams[idx]); + utils::print(out, " {}\n", dbodyparams[idx]); } } } diff --git a/src/molecule.h b/src/molecule.h index 90c350eb889..f6e1c96399d 100644 --- a/src/molecule.h +++ b/src/molecule.h @@ -17,6 +17,7 @@ #include "pointers.h" #include "json_fwd.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -145,7 +146,7 @@ class Molecule : protected Pointers { void print(FILE *fp=stdout); private: - FILE *fp; + SafeFilePtr fp; int *count; int toffset, boffset, aoffset, doffset, ioffset; int json_format; diff --git a/src/read_data.cpp b/src/read_data.cpp index 5ed44816cac..50753a1834f 100644 --- a/src/read_data.cpp +++ b/src/read_data.cpp @@ -90,7 +90,7 @@ bool ReadData::is_data_section(const std::string &keyword) } /* ---------------------------------------------------------------------- */ -ReadData::ReadData(LAMMPS *_lmp) : Command(_lmp), fp(nullptr), coeffarg(nullptr), lmap(nullptr) +ReadData::ReadData(LAMMPS *_lmp) : Command(_lmp), coeffarg(nullptr), lmap(nullptr) { MPI_Comm_rank(world, &me); line = new char[MAXLINE]; @@ -525,8 +525,7 @@ void ReadData::command(int narg, char **arg) if (me == 0) { if (firstpass) utils::logmesg(lmp, "Reading data file ...\n"); open(arg[0]); - } else - fp = nullptr; + } // read header info @@ -1056,16 +1055,6 @@ void ReadData::command(int narg, char **arg) if (natoms > 0 && atomflag == 0) error->all(FLERR, Error::ARGZERO, "No valid atoms found in data file"); - // close file - - if (me == 0) { - if (compressed) - platform::pclose(fp); - else - fclose(fp); - fp = nullptr; - } - // done if this was 2nd pass if (!firstpass) break; @@ -2461,7 +2450,7 @@ int ReadData::reallocate(int **pcount, int cmax, int amax) /* ---------------------------------------------------------------------- proc 0 opens data file - test if compressed + test if compressed and thus need to close with pclose() instead of fclose() ------------------------------------------------------------------------- */ void ReadData::open(const std::string &file) @@ -2469,11 +2458,10 @@ void ReadData::open(const std::string &file) // file may be a redirect, e.g. on a git checkout on Windows in lieu of a symbolic link auto path = platform::file_redirect(file); if (platform::has_compress_extension(path)) { - compressed = 1; + fp.set_pclose(); fp = platform::compressed_read(path); if (!fp) error->one(FLERR, "Cannot open compressed file {}", file); } else { - compressed = 0; fp = fopen(path.c_str(), "r"); if (!fp) error->one(FLERR, "Cannot open file {}: {}", file, utils::getsyserror()); } diff --git a/src/read_data.h b/src/read_data.h index 008283251cd..efa96f190f7 100644 --- a/src/read_data.h +++ b/src/read_data.h @@ -21,6 +21,7 @@ CommandStyle(read_data,ReadData); #define LMP_READ_DATA_H #include "command.h" +#include "safe_pointers.h" namespace LAMMPS_NS { class Fix; @@ -32,9 +33,9 @@ class ReadData : public Command { static bool is_data_section(const std::string &); private: - int me, compressed; + int me; char *line, *keyword, *buffer, *style; - FILE *fp; + SafeFilePtr fp; char **coeffarg; int ncoeffarg, maxcoeffarg; std::string argoffset1, argoffset2; diff --git a/src/reader.cpp b/src/reader.cpp index fccbf990b40..37ff9667a80 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -23,9 +23,7 @@ using namespace LAMMPS_NS; Reader::Reader(LAMMPS *lmp) : Pointers(lmp) { - fp = nullptr; binary = false; - compressed = false; } // avoid resource leak @@ -41,14 +39,11 @@ Reader::~Reader() void Reader::open_file(const std::string &file) { - if (fp != nullptr) close_file(); - if (platform::has_compress_extension(file)) { - compressed = true; + fp.set_pclose(); fp = platform::compressed_read(file); if (!fp) error->one(FLERR, "Cannot open compressed file for reading"); } else { - compressed = false; if (utils::strmatch(file, "\\.bin$")) { binary = true; fp = fopen(file.c_str(), "rb"); @@ -68,11 +63,6 @@ void Reader::open_file(const std::string &file) void Reader::close_file() { - if (fp == nullptr) return; - if (compressed) - platform::pclose(fp); - else - fclose(fp); fp = nullptr; } diff --git a/src/reader.h b/src/reader.h index 88f97517d09..76a3cee98fa 100644 --- a/src/reader.h +++ b/src/reader.h @@ -17,6 +17,7 @@ #define LMP_READER_H #include "pointers.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -40,9 +41,8 @@ class Reader : protected Pointers { virtual void close_file(); protected: - FILE *fp; // pointer to opened file or pipe - bool compressed; // flag for dump file compression - bool binary; // flag for (native) binary files + SafeFilePtr fp; // pointer to opened file or pipe + bool binary; // flag for (native) binary files }; } // namespace LAMMPS_NS From 5ccb918f2990e32ceb4cdc9dd8477f7281f8a1bb Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 16 Mar 2026 11:14:25 -0400 Subject: [PATCH 09/12] convert more classes in src that have a FILE pointer class member to SafeFilePtr --- src/balance.cpp | 4 ---- src/balance.h | 3 ++- src/citeme.cpp | 1 - src/citeme.h | 4 +++- src/fix_ave_chunk.cpp | 10 ++++------ src/fix_ave_chunk.h | 3 ++- src/fix_ave_correlate.cpp | 4 +--- src/fix_ave_correlate.h | 3 ++- src/fix_ave_histo.cpp | 6 ++---- src/fix_ave_histo.h | 3 ++- src/fix_ave_time.cpp | 9 +++------ src/fix_ave_time.h | 3 ++- 12 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/balance.cpp b/src/balance.cpp index 8fca4ceb51e..9ad61556e7d 100644 --- a/src/balance.cpp +++ b/src/balance.cpp @@ -66,7 +66,6 @@ Balance::Balance(LAMMPS *lmp) : Command(lmp) imbalances = nullptr; fixstore = nullptr; - fp = nullptr; firststep = 1; } @@ -102,8 +101,6 @@ Balance::~Balance() if (fixstore && modify->nfix) modify->delete_fix(fixstore->id); fixstore = nullptr; - - if (fp) fclose(fp); } /* ---------------------------------------------------------------------- @@ -436,7 +433,6 @@ void Balance::options(int iarg, int narg, char **arg, int sortflag_default) sortflag = sortflag_default; outflag = 0; int outarg = 0; - fp = nullptr; oldrcb = 0; while (iarg < narg) { diff --git a/src/balance.h b/src/balance.h index 33fe19d838e..fe1e53afeb0 100644 --- a/src/balance.h +++ b/src/balance.h @@ -21,6 +21,7 @@ CommandStyle(balance,Balance); #define LMP_BALANCE_H #include "command.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -78,7 +79,7 @@ class Balance : public Command { class Imbalance **imbalances; // list of Imb classes, one per weight style double *weight; // ptr to FixStore weight vector - FILE *fp; // balance output file + SafeFilePtr fp; // balance output file int firststep; double imbalance_splits(); diff --git a/src/citeme.cpp b/src/citeme.cpp index 35443be49ff..7503b112f89 100644 --- a/src/citeme.cpp +++ b/src/citeme.cpp @@ -79,7 +79,6 @@ CiteMe::CiteMe(LAMMPS *lmp, int _screen, int _logfile, const char *_file) : Poin CiteMe::~CiteMe() { flush(); - if (fp) fclose(fp); } /* ---------------------------------------------------------------------- diff --git a/src/citeme.h b/src/citeme.h index d6ac3acecc2..88dda0bda4c 100644 --- a/src/citeme.h +++ b/src/citeme.h @@ -15,6 +15,8 @@ #define LMP_CITEME_H #include "pointers.h" +#include "safe_pointers.h" + #include namespace LAMMPS_NS { @@ -76,7 +78,7 @@ or is reset by the :doc:`clear ` command and at the end of a }; private: - FILE *fp; /**< File pointer for optional BibTeX citation file or NULL */ + SafeFilePtr fp; /**< Safe file pointer class for optional BibTeX citation file */ std::string citefile; /**< Name of the explicit citation file */ int screen_flag; /**< Output mode for screen (VERBOSE or TERSE) */ int logfile_flag; /**< Output mode for log file (VERBOSE or TERSE) */ diff --git a/src/fix_ave_chunk.cpp b/src/fix_ave_chunk.cpp index ed556f85b73..30093890fb0 100644 --- a/src/fix_ave_chunk.cpp +++ b/src/fix_ave_chunk.cpp @@ -43,10 +43,10 @@ enum { ONE, RUNNING, WINDOW }; FixAveChunk::FixAveChunk(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), nvalues(0), nrepeat(0), format(nullptr), tstring(nullptr), - sstring(nullptr), id_bias(nullptr), tbias(nullptr), fp(nullptr), chunk_volume_vec(nullptr), - idchunk(nullptr), cchunk(nullptr), varatom(nullptr), count_one(nullptr), count_many(nullptr), - count_sum(nullptr), values_one(nullptr), values_many(nullptr), values_sum(nullptr), - count_total(nullptr), count_list(nullptr), values_total(nullptr), values_list(nullptr) + sstring(nullptr), id_bias(nullptr), tbias(nullptr), chunk_volume_vec(nullptr), idchunk(nullptr), + cchunk(nullptr), varatom(nullptr), count_one(nullptr), count_many(nullptr), count_sum(nullptr), + values_one(nullptr), values_many(nullptr), values_sum(nullptr), count_total(nullptr), + count_list(nullptr), values_total(nullptr), values_list(nullptr) { if (narg < 7) utils::missing_cmd_args(FLERR, "fix ave/chunk", error); @@ -403,8 +403,6 @@ FixAveChunk::FixAveChunk(LAMMPS *lmp, int narg, char **arg) : FixAveChunk::~FixAveChunk() { - if (fp && comm->me == 0) fclose(fp); - memory->destroy(varatom); memory->destroy(count_one); memory->destroy(count_many); diff --git a/src/fix_ave_chunk.h b/src/fix_ave_chunk.h index 01dd4965cf4..09325d25cd3 100644 --- a/src/fix_ave_chunk.h +++ b/src/fix_ave_chunk.h @@ -21,6 +21,7 @@ FixStyle(ave/chunk,FixAveChunk); #define LMP_FIX_AVE_CHUNK_H #include "fix.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -56,7 +57,7 @@ class FixAveChunk : public Fix { char *format; char *tstring, *sstring, *id_bias; class Compute *tbias; // ptr to additional bias compute - FILE *fp; + SafeFilePtr fp; int densityflag; // 1 if density/number or density/mass requested int volflag; // SCALAR/VECTOR for density normalization by volume diff --git a/src/fix_ave_correlate.cpp b/src/fix_ave_correlate.cpp index 2007acd1602..70bdd1cbcc2 100644 --- a/src/fix_ave_correlate.cpp +++ b/src/fix_ave_correlate.cpp @@ -41,7 +41,7 @@ enum { AUTO, UPPER, LOWER, AUTOUPPER, AUTOLOWER, FULL, FIRST }; /* ---------------------------------------------------------------------- */ FixAveCorrelate::FixAveCorrelate(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), fp(nullptr), count(nullptr), cvalues(nullptr), corr(nullptr), + Fix(lmp, narg, arg), count(nullptr), cvalues(nullptr), corr(nullptr), save_count(nullptr), save_corr(nullptr) { if (narg < 7) utils::missing_cmd_args(FLERR, "fix ave/correlate", error); @@ -326,8 +326,6 @@ FixAveCorrelate::~FixAveCorrelate() memory->destroy(save_count); memory->destroy(corr); memory->destroy(save_corr); - - if (fp && comm->me == 0) fclose(fp); } /* ---------------------------------------------------------------------- */ diff --git a/src/fix_ave_correlate.h b/src/fix_ave_correlate.h index be322ff11a7..5bd6ae3809c 100644 --- a/src/fix_ave_correlate.h +++ b/src/fix_ave_correlate.h @@ -21,6 +21,7 @@ FixStyle(ave/correlate,FixAveCorrelate); #define LMP_FIX_AVE_CORRELATE_H #include "fix.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -50,7 +51,7 @@ class FixAveCorrelate : public Fix { int nvalues, nrepeat, nfreq; bigint nvalid, nvalid_last; - FILE *fp; + SafeFilePtr fp; int type, ave, startstep, overwrite; double prefactor; diff --git a/src/fix_ave_histo.cpp b/src/fix_ave_histo.cpp index f660567545e..2a36f96219f 100644 --- a/src/fix_ave_histo.cpp +++ b/src/fix_ave_histo.cpp @@ -39,8 +39,8 @@ static constexpr double BIG = 1.0e20; /* ---------------------------------------------------------------------- */ FixAveHisto::FixAveHisto(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), nvalues(0), fp(nullptr), stats_list(nullptr), bin(nullptr), - bin_total(nullptr), bin_all(nullptr), bin_list(nullptr), coord(nullptr), vector(nullptr) + Fix(lmp, narg, arg), nvalues(0), stats_list(nullptr), bin(nullptr), bin_total(nullptr), + bin_all(nullptr), bin_list(nullptr), coord(nullptr), vector(nullptr) { const auto mycmd = fmt::format("fix {}", style); if (narg < 10) utils::missing_cmd_args(FLERR, mycmd, error); @@ -438,8 +438,6 @@ FixAveHisto::FixAveHisto(LAMMPS *lmp, int narg, char **arg) : FixAveHisto::~FixAveHisto() { - if (fp && comm->me == 0) fclose(fp); - delete[] bin; delete[] bin_total; delete[] bin_all; diff --git a/src/fix_ave_histo.h b/src/fix_ave_histo.h index a8c4c2ecd81..c27e9175f57 100644 --- a/src/fix_ave_histo.h +++ b/src/fix_ave_histo.h @@ -21,6 +21,7 @@ FixStyle(ave/histo,FixAveHisto); #define LMP_FIX_AVE_HISTO_H #include "fix.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -52,7 +53,7 @@ class FixAveHisto : public Fix { int nvalues, nrepeat, nfreq, irepeat; bigint nvalid, nvalid_last; - FILE *fp; + SafeFilePtr fp; double lo, hi, binsize, bininv; int kind, beyond, overwrite; bigint filepos; diff --git a/src/fix_ave_time.cpp b/src/fix_ave_time.cpp index 74c642ca866..33ff09c968f 100644 --- a/src/fix_ave_time.cpp +++ b/src/fix_ave_time.cpp @@ -39,7 +39,7 @@ enum { SCALAR, VECTOR }; /* ---------------------------------------------------------------------- */ FixAveTime::FixAveTime(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), nvalues(0), fp(nullptr), offlist(nullptr), format(nullptr), vector(nullptr), + Fix(lmp, narg, arg), nvalues(0), offlist(nullptr), format(nullptr), vector(nullptr), vector_total(nullptr), vector_list(nullptr), column(nullptr), array(nullptr), array_total(nullptr), array_list(nullptr) { @@ -449,10 +449,8 @@ FixAveTime::~FixAveTime() delete[] format; delete[] extlist; - if (fp && comm->me == 0) { - if (yaml_flag) fputs("...\n", fp); - fclose(fp); - } + if (fp && (comm->me == 0) && yaml_flag) fputs("...\n", fp); + memory->destroy(column); delete[] vector; @@ -1013,7 +1011,6 @@ void FixAveTime::options(int iarg, int narg, char **arg) { // option defaults - fp = nullptr; ave = ONE; startstep = 0; mode = SCALAR; diff --git a/src/fix_ave_time.h b/src/fix_ave_time.h index 7e16b0e3171..69484c1fe22 100644 --- a/src/fix_ave_time.h +++ b/src/fix_ave_time.h @@ -21,6 +21,7 @@ FixStyle(ave/time,FixAveTime); #define LMP_FIX_AVE_TIME_H #include "fix.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -56,7 +57,7 @@ class FixAveTime : public Fix { int nvalues, nrepeat, nfreq, irepeat; bigint nvalid, nvalid_last; - FILE *fp; + SafeFilePtr fp; int nrows; int any_variable_length; int all_variable_length; From 0cdb197bb879c83856906376046504fe4bf13db1 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 16 Mar 2026 11:29:50 -0400 Subject: [PATCH 10/12] convert a few more cases to use SafeFilePtr --- src/min_hftn.cpp | 14 +------------- src/min_hftn.h | 4 ++-- src/pair.cpp | 5 ++--- src/procmap.cpp | 18 +++++++----------- 4 files changed, 12 insertions(+), 29 deletions(-) diff --git a/src/min_hftn.cpp b/src/min_hftn.cpp index 5db8c0e98d5..35157ddb609 100644 --- a/src/min_hftn.cpp +++ b/src/min_hftn.cpp @@ -85,8 +85,6 @@ MinHFTN::MinHFTN(LAMMPS *lmp) : Min(lmp) _daExtraGlobal[i] = nullptr; for (int i = 0; i < NUM_HFTN_ATOM_BASED_VECTORS; i++) _daExtraAtom[i] = nullptr; - - _fpPrint = nullptr; } /* ---------------------------------------------------------------------- @@ -214,8 +212,6 @@ int MinHFTN::iterate(int) dFinalEnergy, dFinalFnorm2); modify->min_clearstore(); - if (bPrintProgress) - close_hftn_print_file_(); return( nStopCode ); } @@ -1599,7 +1595,7 @@ void MinHFTN::open_hftn_print_file_() MPI_Comm_rank (world, &nMyRank); auto szTmp = fmt::format("progress_MinHFTN_{}.txt", nMyRank); - _fpPrint = fopen (szTmp.c_str(), "w"); + _fpPrint = fopen(szTmp.c_str(), "w"); if (_fpPrint == nullptr) return; fprintf (_fpPrint, " Iter Evals Energy |F|_2" @@ -1671,11 +1667,3 @@ void MinHFTN::hftn_print_line_(const bool bIsStepAccepted, fflush (_fpPrint); } -/* ---------------------------------------------------------------------- - Private method close_hftn_print_file_ -------------------------------------------------------------------------- */ - -void MinHFTN::close_hftn_print_file_() -{ - if (_fpPrint != nullptr) fclose (_fpPrint); -} diff --git a/src/min_hftn.h b/src/min_hftn.h index a7a4e61729e..4fb112aadb5 100644 --- a/src/min_hftn.h +++ b/src/min_hftn.h @@ -21,6 +21,7 @@ MinimizeStyle(hftn,MinHFTN); #define LMP_MIN_HFTN_H #include "min.h" +#include "safe_pointers.h" namespace LAMMPS_NS { @@ -55,7 +56,7 @@ class MinHFTN : public Min { double *_daExtraGlobal[NUM_HFTN_ATOM_BASED_VECTORS]; int _nNumUnknowns; - FILE *_fpPrint; + SafeFilePtr _fpPrint; int execute_hftn_(const bool bPrintProgress, const double dInitialEnergy, const double dInitialForce2, double &dFinalEnergy, double &dFinalForce2); @@ -84,7 +85,6 @@ class MinHFTN : public Min { const double dEnergy, const double dForce2, const int nStepType, const double dTrustRadius, const double dStepLength2, const double dActualRed, const double dPredictedRed) const; - void close_hftn_print_file_(); }; } // namespace LAMMPS_NS diff --git a/src/pair.cpp b/src/pair.cpp index f511dd90d54..ca8eeb0db3f 100644 --- a/src/pair.cpp +++ b/src/pair.cpp @@ -30,6 +30,7 @@ #include "math_special.h" #include "memory.h" #include "neighbor.h" +#include "safe_pointers.h" #include "suffix.h" #include "update.h" @@ -1837,7 +1838,7 @@ void Pair::write_file(int narg, char **arg) // add line with DATE: and UNITS: tag when creating new file // print header in format used by pair_style table - FILE *fp = nullptr; + SafeFilePtr fp; if (comm->me == 0) { std::string table_file = arg[6]; @@ -1952,8 +1953,6 @@ void Pair::write_file(int narg, char **arg) double *tmp; if (epair) epair->swap_eam(eamfp_hold, &tmp); if (atom->q) atom->q = q_hold; - - if (comm->me == 0) fclose(fp); } /* ---------------------------------------------------------------------- diff --git a/src/procmap.cpp b/src/procmap.cpp index 9b51e69df07..d01f2cfa082 100644 --- a/src/procmap.cpp +++ b/src/procmap.cpp @@ -23,6 +23,7 @@ #include "error.h" #include "math_extra.h" #include "memory.h" +#include "safe_pointers.h" #include "tokenizer.h" #include "universe.h" @@ -267,11 +268,12 @@ void ProcMap::custom_grid(char *cfile, int nprocs, MPI_Comm_rank(world,&me); char line[MAXLINE] = {'\0'}; - FILE *fp = nullptr; + SafeFilePtr fp; if (me == 0) { fp = fopen(cfile,"r"); - if (fp == nullptr) error->one(FLERR,"Cannot open custom file"); + if (fp == nullptr) + error->one(FLERR,"Cannot open custom grid file {}: {}", cfile, utils::getsyserror()); // skip header = blank and comment lines @@ -293,8 +295,7 @@ void ProcMap::custom_grid(char *cfile, int nprocs, procgrid[1] = procs.next_int(); procgrid[2] = procs.next_int(); } catch (TokenizerException &e) { - error->all(FLERR,"Processors custom grid file " - "is inconsistent: {}", e.what()); + error->all(FLERR,"Processors custom grid file {} is inconsistent: {}", cfile, e.what()); } int flag = 0; @@ -302,7 +303,7 @@ void ProcMap::custom_grid(char *cfile, int nprocs, if (user_procgrid[0] && procgrid[0] != user_procgrid[0]) flag = 1; if (user_procgrid[1] && procgrid[1] != user_procgrid[1]) flag = 1; if (user_procgrid[2] && procgrid[2] != user_procgrid[2]) flag = 1; - if (flag) error->all(FLERR,"Processors custom grid file is inconsistent"); + if (flag) error->all(FLERR,"Processors custom grid file {} is inconsistent", cfile); // cmap = map of procs to grid // store for use in custom_map() @@ -326,7 +327,6 @@ void ProcMap::custom_grid(char *cfile, int nprocs, "inconsistent: {}", e.what()); } } - fclose(fp); } MPI_Bcast(&cmap[0][0],nprocs*4,MPI_INT,0,world); @@ -656,7 +656,7 @@ void ProcMap::output(char *file, int *procgrid, int ***grid2proc) MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); - FILE *fp; + SafeFilePtr fp; if (me == 0) { fp = fopen(file,"w"); if (fp == nullptr) error->one(FLERR,"Cannot open processors output file"); @@ -711,10 +711,6 @@ void ProcMap::output(char *file, int *procgrid, int ***grid2proc) MPI_Send(vec,6,MPI_INT,0,0,world); MPI_Send(procname,strlen(procname)+1,MPI_CHAR,0,0,world); } - - // close output file - - if (me == 0) fclose(fp); } /* ---------------------------------------------------------------------- From ae121459c2e20161530d3e3a8f6e6be38d1814e1 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 16 Mar 2026 19:47:49 -0400 Subject: [PATCH 11/12] convert dump styles to use SafeFilePtr --- src/EXTRA-DUMP/dump_xtc.cpp | 2 -- src/GRAPHICS/dump_image.cpp | 3 +-- src/dump.cpp | 32 ++++++++------------------------ src/dump.h | 31 ++++++++++++++++--------------- 4 files changed, 25 insertions(+), 43 deletions(-) diff --git a/src/EXTRA-DUMP/dump_xtc.cpp b/src/EXTRA-DUMP/dump_xtc.cpp index cc0366bd7de..23874037cc8 100644 --- a/src/EXTRA-DUMP/dump_xtc.cpp +++ b/src/EXTRA-DUMP/dump_xtc.cpp @@ -149,9 +149,7 @@ void DumpXTC::init_style() void DumpXTC::openfile() { // XTC maintains it's own XDR file ptr - // set fp to a null pointer so parent dump class will not use it - fp = nullptr; if (me == 0) if (xdropen(xd,filename,"w") == 0) error->one(FLERR,"Cannot open XTC format dump file {}: {}", filename, utils::getsyserror()); diff --git a/src/GRAPHICS/dump_image.cpp b/src/GRAPHICS/dump_image.cpp index 015dac6fad4..d36230e64a6 100644 --- a/src/GRAPHICS/dump_image.cpp +++ b/src/GRAPHICS/dump_image.cpp @@ -1042,8 +1042,7 @@ void DumpImage::write() else if (filetype == TGA) image->write_TGA(fp); else image->write_PPM(fp); if (multifile) { - fclose(fp); - fp = nullptr; + fp = nullptr; // implicitly close file // cache last dump image filename for access through library interface. // update only *after* the file has been written so there will be no invalid read. diff --git a/src/dump.cpp b/src/dump.cpp index ea8e849ca68..4e53dfc805d 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -47,7 +47,7 @@ enum { ASCEND, DESCEND }; Dump::Dump(LAMMPS *lmp, int /*narg*/, char **arg) : Pointers(lmp), multiname(nullptr), idrefresh(nullptr), irefresh(nullptr), skipvar(nullptr), format(nullptr), format_default(nullptr), format_line_user(nullptr), format_float_user(nullptr), - format_int_user(nullptr), format_bigint_user(nullptr), format_column_user(nullptr), fp(nullptr), + format_int_user(nullptr), format_bigint_user(nullptr), format_column_user(nullptr), nameslist(nullptr), buf(nullptr), sbuf(nullptr), ids(nullptr), bufsort(nullptr), idsort(nullptr), index(nullptr), proclist(nullptr), xpbc(nullptr), vpbc(nullptr), imagepbc(nullptr), irregular(nullptr) @@ -183,17 +183,6 @@ Dump::~Dump() for (int idx = 0; idx < numfiles; ++idx) delete[] nameslist[idx]; delete[] nameslist; } - - // XTC style sets fp to a null pointer since it closes file in its destructor - - if (multifile == 0 && fp != nullptr) { - if (compressed) { - if (filewriter) platform::pclose(fp); - } else { - if (filewriter) fclose(fp); - } - fp = nullptr; - } } // clang-format off @@ -544,16 +533,9 @@ void Dump::write() if (fp && ferror(fp)) error->one(FLERR, Error::NOLASTLINE, "Error writing dump {}: {}", id, utils::getsyserror()); - // if file per timestep, close file if I am filewriter + // if file per timestep, close open files - if (multifile) { - if (compressed) { - if (filewriter && fp != nullptr) platform::pclose(fp); - } else { - if (filewriter && fp != nullptr) fclose(fp); - } - fp = nullptr; - } + if (multifile) fp = nullptr; // implicitly closes file } /* ---------------------------------------------------------------------- @@ -595,6 +577,7 @@ void Dump::openfile() if (filewriter) { if (compressed) { + fp.set_pclose(); fp = platform::compressed_write(filecurrent); } else if (binary) { fp = fopen(filecurrent,"wb"); @@ -604,10 +587,11 @@ void Dump::openfile() fp = fopen(filecurrent,"w"); } - if (fp == nullptr) - error->one(FLERR, Error::NOLASTLINE, "Cannot open dump file {}:{}", + if (fp == nullptr) { + error->one(FLERR, Error::NOLASTLINE, "Cannot open dump file {}: {}", filecurrent, utils::getsyserror()); - } else fp = nullptr; + } + } // delete string with timestep replaced diff --git a/src/dump.h b/src/dump.h index 03d7c01ad9b..c2fd45e2477 100644 --- a/src/dump.h +++ b/src/dump.h @@ -15,6 +15,7 @@ #define LMP_DUMP_H #include "pointers.h" // IWYU pragma: export +#include "safe_pointers.h" #include @@ -60,17 +61,17 @@ class Dump : protected Pointers { protected: int me, nprocs; // proc info - int compressed; // 1 if dump file is written compressed, 0 no - int binary; // 1 if dump file is written binary, 0 no - int multifile; // 0 = one big file, 1 = one file per timestep - int multifile_override; // 1 to override the "must have '*'" restriction in `write_dump` - int multiproc; // 0 = proc 0 writes for all, - // else # of procs writing files - int nclusterprocs; // # of procs in my cluster that write to one file - int filewriter; // 1 if this proc writes a file, else 0 - int fileproc; // ID of proc in my cluster who writes to file - char *multiname; // filename with % converted to cluster ID - MPI_Comm clustercomm; // MPI communicator within my cluster of procs + int compressed; // 1 if dump file is written compressed, 0 no + int binary; // 1 if dump file is written binary, 0 no + int multifile; // 0 = one big file, 1 = one file per timestep + int multifile_override; // 1 to override the "must have '*'" restriction in `write_dump` + int multiproc; // 0 = proc 0 writes for all, + // else # of procs writing files + int nclusterprocs; // # of procs in my cluster that write to one file + int filewriter; // 1 if this proc writes a file, else 0 + int fileproc; // ID of proc in my cluster who writes to file + char *multiname; // filename with % converted to cluster ID + MPI_Comm clustercomm; // MPI communicator within my cluster of procs int flush_flag; // 0 if no flush, 1 if flush every dump int sort_flag; // 1 if sorted output @@ -115,10 +116,10 @@ class Dump : protected Pointers { std::map key2col; std::vector keyword_user; - FILE *fp; // file to write dump to - int size_one; // # of quantities for one atom - int nme; // # of atoms in this dump from me - int nsme; // # of chars in string output from me + SafeFilePtr fp; // file to write dump to + int size_one; // # of quantities for one atom + int nme; // # of atoms in this dump from me + int nsme; // # of chars in string output from me double boxxlo, boxxhi; // local copies of domain values double boxylo, boxyhi; // lo/hi are bounding box for triclinic From 01b2f2b4ebf74cd621ef39f816cfc4e7ac43bc3d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2026 22:42:03 -0400 Subject: [PATCH 12/12] apply corrections and improvements suggested by copilot --- doc/src/Developer_utils.rst | 8 +++++--- src/platform.cpp | 1 + src/safe_pointers.cpp | 1 + src/safe_pointers.h | 19 +++++++++++++++++-- src/write_coeff.cpp | 1 + 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/doc/src/Developer_utils.rst b/doc/src/Developer_utils.rst index c39e6035ea7..0ce2bd31f62 100644 --- a/doc/src/Developer_utils.rst +++ b/doc/src/Developer_utils.rst @@ -501,9 +501,11 @@ A typical code segment would look like this: Safe pointer classes -------------------- -These are custom classes to support the `Resource acquisition is initialization -(RIAA) `_ -programming idiom in LAMMPS for certain types of pointers. Currently there is: +These are custom classes to support the `Resource Acquisition Is +Initialization (RAII) +`_ +programming idiom in LAMMPS for certain types of pointers. Currently +there is: .. doxygenclass:: LAMMPS_NS::SafeFilePtr :project: progguide diff --git a/src/platform.cpp b/src/platform.cpp index e5f7b82949d..a3848d13768 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -994,6 +994,7 @@ bool platform::file_is_writable(const std::string &path) } else { fp = fopen(path.c_str(), "w"); if (fp) { + fp = nullptr; unlink(path); return true; } diff --git a/src/safe_pointers.cpp b/src/safe_pointers.cpp index 7952ddabba8..670c094e6eb 100644 --- a/src/safe_pointers.cpp +++ b/src/safe_pointers.cpp @@ -38,5 +38,6 @@ SafeFilePtr &SafeFilePtr::operator=(FILE *_fp) fclose(fp); } fp = _fp; + if (_fp == nullptr) use_pclose = false; return *this; } diff --git a/src/safe_pointers.h b/src/safe_pointers.h index 327ab70f635..66beb42430f 100644 --- a/src/safe_pointers.h +++ b/src/safe_pointers.h @@ -43,9 +43,11 @@ Below are some usage examples: fp = fopen("some.file","r"); // a second assignment will automatically close the opened file fp = fopen("other.file", "r"); + // and assigning nullptr will just close it + fp = nullptr; // There also is a custom constructor available as a shortcut - SafeFilePtr fp(fopen("some.file", "r"); + SafeFilePtr fp(fopen("some.file", "r")); // You can indicate that a file was opened with popen() to call pclose() instead of fclose() SafeFilePtr fp; @@ -60,7 +62,7 @@ Below are some usage examples: // reading or writing works without needing to change the source code fputs("write text to file\n", fp); char buffer[100]; - utils::sfgets(FILE, buffer, 100, fp, filename, error); + utils::sfgets(FLERR, buffer, 100, fp, filename, error); \endverbatim */ @@ -75,8 +77,21 @@ class SafeFilePtr { ~SafeFilePtr(); + /** Assign new file pointer and close old one if still open. + * + * The value of use_pclose determines whether `pclose()` is called or `fclose()`. + * Assigning `nullptr` closes the file and resets use_pclose + * + * \param _fp new file pointer, may be `nullptr` + * \return reference to updated class instance */ SafeFilePtr &operator=(FILE *_fp); + + /** Flag that the file pointer needs to be closed with `pclose()` instead of `fclose()` */ void set_pclose() { use_pclose = true; } + + /** Custom type cast operator so that SafeFilePtr can be used where FILE * was used + * + * \return currently stored/monitored file pointer */ operator FILE *() const { return fp; } private: diff --git a/src/write_coeff.cpp b/src/write_coeff.cpp index 8a395c2b213..95fcfc2be4b 100644 --- a/src/write_coeff.cpp +++ b/src/write_coeff.cpp @@ -164,6 +164,7 @@ void WriteCoeff::command(int narg, char **arg) } fputc('\n', two); } + one = nullptr; // implicitly close file platform::unlink(file); } delete[] file;