Modernize write_inpfile
authorMark Abraham <mark.j.abraham@gmail.com>
Sun, 1 Jan 2017 10:13:13 +0000 (10:13 +0000)
committerMark Abraham <mark.j.abraham@gmail.com>
Mon, 13 Mar 2017 16:09:05 +0000 (17:09 +0100)
Used std::string, gmx::TextOutputFile and gmx::TextWriter to simplify
and permit testing.

To do so, modified the interface of various helper functionality so
that it can use a TextWriter that the caller could build with
something other than a FILE stream if they wanted to. This would also
be more convenient for testing them, if we ever do that.

Moved nice_header to utility/niceheader.h, renamed it
niceHeader, and permitted its caller to specify the comment character.

Moved string-handling behaviour out of cuda_version_information,
while ensuring no C++11 functionality is needed.

Updated documentation of intended scope of sysinfo.h, and removed c++
guard.

Change-Id: I6ab250c982a8e9e9ee3dacb6575ccc04f17e689c

15 files changed:
src/gromacs/fileio/readinp.cpp
src/gromacs/fileio/readinp.h
src/gromacs/gmxana/gmx_xpm2ps.cpp
src/gromacs/gmxpreprocess/pdb2top.cpp
src/gromacs/gmxpreprocess/readir.cpp
src/gromacs/utility/binaryinformation.cpp
src/gromacs/utility/binaryinformation.h
src/gromacs/utility/cstringutil.cpp
src/gromacs/utility/cstringutil.h
src/gromacs/utility/cuda_version_information.cu
src/gromacs/utility/cuda_version_information.h
src/gromacs/utility/niceheader.cpp [new file with mode: 0644]
src/gromacs/utility/niceheader.h [new file with mode: 0644]
src/gromacs/utility/sysinfo.h
src/programs/mdrun/membed.cpp

index aeaa00c2b6311c2dacdb76d1c4b8513839ccefe3..9784114e83389ced4aa6e1640b2b12e7415e395a 100644 (file)
 
 #include "readinp.h"
 
-#include <cstdio>
 #include <cstdlib>
 #include <cstring>
 
 #include <algorithm>
 
-#include "gromacs/fileio/gmxfio.h"
 #include "gromacs/fileio/warninp.h"
 #include "gromacs/utility/binaryinformation.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/niceheader.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/qsort_threadsafe.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
 #include "gromacs/utility/textreader.h"
-#include "gromacs/utility/textstream.h"
+#include "gromacs/utility/textwriter.h"
 
 t_inpfile *read_inpfile(gmx::TextInputStream *stream, const char *fn, int *ninp,
                         warninp_t wi)
@@ -197,56 +196,53 @@ static void sort_inp(int ninp, t_inpfile inp[])
     gmx_qsort(inp, ninp, static_cast<size_t>(sizeof(inp[0])), inp_comp);
 }
 
-void write_inpfile(const char *fn, int ninp, t_inpfile inp[], gmx_bool bHaltOnUnknown,
+void write_inpfile(gmx::TextOutputStream *stream, const char *fn, int ninp, t_inpfile inp[],
+                   gmx_bool bHaltOnUnknown,
                    WriteMdpHeader writeHeader,
                    warninp_t wi)
 {
-    FILE *out;
-    int   i;
-    char  warn_buf[STRLEN];
+    using gmx::formatString;
 
     sort_inp(ninp, inp);
-    out = gmx_fio_fopen(fn, "w");
+
+    gmx::TextWriter writer(stream);
     if (writeHeader == WriteMdpHeader::yes)
     {
-        nice_header(out, fn);
-        try
-        {
-            gmx::BinaryInformationSettings settings;
-            settings.generatedByHeader(true);
-            settings.linePrefix(";\t");
-            gmx::printBinaryInformation(out, gmx::getProgramContext(), settings);
-        }
-        GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+        gmx::niceHeader(&writer, fn, ';');
+
+        gmx::BinaryInformationSettings settings;
+        settings.generatedByHeader(true);
+        settings.linePrefix(";\t");
+        gmx::printBinaryInformation(&writer, gmx::getProgramContext(), settings);
     }
-    for (i = 0; (i < ninp); i++)
+
+    for (int i = 0; (i < ninp); i++)
     {
         if (inp[i].bSet)
         {
             if (inp[i].name[0] == ';' || (strlen(inp[i].name) > 2 && inp[i].name[1] == ';'))
             {
-                fprintf(out, "%-24s\n", inp[i].name);
+                writer.writeLine(formatString("%-24s", inp[i].name));
             }
             else
             {
-                fprintf(out, "%-24s = %s\n", inp[i].name, inp[i].value ? inp[i].value : "");
+                writer.writeLine(formatString("%-24s = %s", inp[i].name, inp[i].value ? inp[i].value : ""));
             }
         }
         else if (!inp[i].bObsolete)
         {
-            sprintf(warn_buf, "Unknown left-hand '%s' in parameter file\n",
-                    inp[i].name);
+            auto message = formatString("Unknown left-hand '%s' in parameter file\n",
+                                        inp[i].name);
             if (bHaltOnUnknown)
             {
-                warning_error(wi, warn_buf);
+                warning_error(wi, message.c_str());
             }
             else
             {
-                warning(wi, warn_buf);
+                warning(wi, message.c_str());
             }
         }
     }
-    gmx_fio_fclose(out);
 
     check_warning_error(wi, FARGS);
 }
index ca020eaf52b5365aa39207569ed601cd03857130..623f6dcc325e0eeffc7ea3bc2f154bdd492fd3c2 100644 (file)
@@ -48,6 +48,7 @@ namespace gmx
 {
 class KeyValueTreeObject;
 class TextInputStream;
+class TextOutputStream;
 }
 
 typedef struct t_inpfile {
@@ -82,7 +83,18 @@ enum class WriteMdpHeader
     no, yes
 };
 
-void write_inpfile(const char *fn, int ninp, t_inpfile inp[],
+/*! \brief Write "key = value" lines from \c inp to \c stream.
+ *
+ * \param[in]  stream          Text stream to write.
+ * \param[in]  fn              Filename corresponding to \c stream.
+ * \param[in]  ninp            Length of \c inp.
+ * \param[in]  inp             Array of key-value pairs.
+ * \param[in]  bHaltOnUnknown  Whether to issue a fatal error if an unknown key is found.
+ * \param[in]  writeHeader     Whether to write a header recording some context a user might like.
+ * \param[out] wi              Handler for context-sensitive warnings.
+ * \throws     std::bad_alloc  If out of memory.
+ * \throws     Anything the stream underlying \c writer can throw. */
+void write_inpfile(gmx::TextOutputStream *stream, const char *fn, int ninp, t_inpfile inp[],
                    gmx_bool bHaltOnUnknown,
                    WriteMdpHeader writeHeader,
                    warninp_t wi);
index b9b7b08b7211e01fe8b1141675cbbd846701e6bf..cec4fe8ca105cf12b85572667673967b1a332341 100644 (file)
@@ -179,7 +179,9 @@ void get_params(const char *mpin, const char *mpout, t_psrec *psr)
 
     if (mpout != nullptr)
     {
-        write_inpfile(mpout, ninp, inp, TRUE, WriteMdpHeader::yes, wi);
+        gmx::TextOutputFile stream(mpout);
+        write_inpfile(&stream, mpout, ninp, inp, TRUE, WriteMdpHeader::yes, wi);
+        stream.close();
     }
 
     done_warning(wi, FARGS);
index 81ab04fc9f5b2d0c7c5dc552fa0e1da414df8ece..dad86e404ae50fee96c67050bbcf06130dc32e6e 100644 (file)
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
+#include "gromacs/utility/niceheader.h"
 #include "gromacs/utility/path.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/strdb.h"
 #include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/textwriter.h"
 
 /* this must correspond to enum in pdb2top.h */
 const char *hh[ehisNR]   = { "HISD", "HISE", "HISH", "HIS1" };
@@ -549,14 +551,17 @@ void print_top_comment(FILE       *out,
     char  ffdir_parent[STRLEN];
     char *p;
 
-    nice_header(out, filename);
-    fprintf(out, ";\tThis is a %s topology file\n;\n", bITP ? "include" : "standalone");
     try
     {
+        gmx::TextWriter writer(out);
+        gmx::niceHeader(&writer, filename, ';');
+        writer.writeLine(gmx::formatString(";\tThis is a %s topology file", bITP ? "include" : "standalone"));
+        writer.writeLine(";");
+
         gmx::BinaryInformationSettings settings;
         settings.generatedByHeader(true);
         settings.linePrefix(";\t");
-        gmx::printBinaryInformation(out, gmx::getProgramContext(), settings);
+        gmx::printBinaryInformation(&writer, gmx::getProgramContext(), settings);
     }
     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
 
index a2f40e27b83e2490fa9b54ca2abb2fd3b65dd626..bb8e44bb2cb5ed001bb3d861100118eb0a8ec6ce 100644 (file)
@@ -2353,7 +2353,12 @@ void get_ir(const char *mdparin, const char *mdparout,
     RTYPE ("userreal4",   ir->userreal4,  0);
 #undef CTYPE
 
-    write_inpfile(mdparout, ninp, inp, FALSE, writeMdpHeader, wi);
+    {
+        gmx::TextOutputFile stream(mdparout);
+        write_inpfile(&stream, mdparout, ninp, inp, FALSE, writeMdpHeader, wi);
+        stream.close();
+    }
+
     for (i = 0; (i < ninp); i++)
     {
         sfree(inp[i].name);
index a366b2f827606a9500156c48f770c32855e448ba..6e9e627f12b92db476c2a59e0d3dffffa9c87bb8 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2017, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -68,6 +68,7 @@
 #include <cstring>
 
 #include <algorithm>
+#include <string>
 
 /* This file is completely threadsafe - keep it that way! */
 
 #include "gromacs/utility/path.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/textwriter.h"
 
 #include "cuda_version_information.h"
 
 namespace
 {
 
+using gmx::formatString;
+
 //! \cond Doxygen does not need to care about most of this stuff, and the macro usage is painful to document
 
 int centeringOffset(int width, int length)
@@ -92,13 +96,13 @@ int centeringOffset(int width, int length)
     return std::max(width - length, 0) / 2;
 }
 
-void printCentered(FILE *fp, int width, const char *text)
+std::string formatCentered(int width, const char *text)
 {
     const int offset = centeringOffset(width, std::strlen(text));
-    fprintf(fp, "%*s%s", offset, "", text);
+    return formatString("%*s%s", offset, "", text);
 }
 
-void printCopyright(FILE *fp)
+void printCopyright(gmx::TextWriter *writer)
 {
     static const char * const Contributors[] = {
         "Emile Apol",
@@ -157,8 +161,8 @@ void printCopyright(FILE *fp)
 #define NLICENSE (int)asize(LicenseText)
 #endif
 
-    printCentered(fp, 78, "GROMACS is written by:");
-    fprintf(fp, "\n");
+    // TODO a centering behaviour of TextWriter could be useful here
+    writer->writeLine(formatCentered(78, "GROMACS is written by:"));
     for (int i = 0; i < NCONTRIBUTORS; )
     {
         for (int j = 0; j < 4 && i < NCONTRIBUTORS; ++j, ++i)
@@ -170,22 +174,21 @@ void printCopyright(FILE *fp)
                                "Formatting buffer is not long enough");
             std::fill(buf, buf+width, ' ');
             std::strcpy(buf+offset, Contributors[i]);
-            fprintf(fp, " %-*s", width, buf);
+            writer->writeString(formatString(" %-*s", width, buf));
         }
-        fprintf(fp, "\n");
+        writer->ensureLineBreak();
     }
-    printCentered(fp, 78, "and the project leaders:");
-    fprintf(fp, "\n");
-    printCentered(fp, 78, "Mark Abraham, Berk Hess, Erik Lindahl, and David van der Spoel");
-    fprintf(fp, "\n\n");
+    writer->writeLine(formatCentered(78, "and the project leaders:"));
+    writer->writeLine(formatCentered(78, "Mark Abraham, Berk Hess, Erik Lindahl, and David van der Spoel"));
+    writer->ensureEmptyLine();
     for (int i = 0; i < NCR; ++i)
     {
-        fprintf(fp, "%s\n", CopyrightText[i]);
+        writer->writeLine(CopyrightText[i]);
     }
-    fprintf(fp, "\n");
+    writer->ensureEmptyLine();
     for (int i = 0; i < NLICENSE; ++i)
     {
-        fprintf(fp, "%s\n", LicenseText[i]);
+        writer->writeLine(LicenseText[i]);
     }
 }
 
@@ -214,96 +217,101 @@ const char *getFftDescriptionString()
 #endif
 };
 
-void gmx_print_version_info(FILE *fp)
+void gmx_print_version_info(gmx::TextWriter *writer)
 {
-    fprintf(fp, "GROMACS version:    %s\n", gmx_version());
+    writer->writeLine(formatString("GROMACS version:    %s", gmx_version()));
     const char *const git_hash = gmx_version_git_full_hash();
     if (git_hash[0] != '\0')
     {
-        fprintf(fp, "GIT SHA1 hash:      %s\n", git_hash);
+        writer->writeLine(formatString("GIT SHA1 hash:      %s", git_hash));
     }
     const char *const base_hash = gmx_version_git_central_base_hash();
     if (base_hash[0] != '\0')
     {
-        fprintf(fp, "Branched from:      %s\n", base_hash);
+        writer->writeLine(formatString("Branched from:      %s", base_hash));
     }
 
 #if GMX_DOUBLE
-    fprintf(fp, "Precision:          double\n");
+    writer->writeLine("Precision:          double");
 #else
-    fprintf(fp, "Precision:          single\n");
+    writer->writeLine("Precision:          single");
 #endif
-    fprintf(fp, "Memory model:       %u bit\n", (unsigned)(8*sizeof(void *)));
+    writer->writeLine(formatString("Memory model:       %u bit", (unsigned)(8*sizeof(void *))));
 
 #if GMX_THREAD_MPI
-    fprintf(fp, "MPI library:        thread_mpi\n");
+    writer->writeLine("MPI library:        thread_mpi");
 #elif GMX_MPI
-    fprintf(fp, "MPI library:        MPI\n");
+    writer->writeLine("MPI library:        MPI");
 #else
-    fprintf(fp, "MPI library:        none\n");
+    writer->writeLine("MPI library:        none");
 #endif
 #if GMX_OPENMP
-    fprintf(fp, "OpenMP support:     enabled (GMX_OPENMP_MAX_THREADS = %d)\n", GMX_OPENMP_MAX_THREADS);
+    writer->writeLine(formatString("OpenMP support:     enabled (GMX_OPENMP_MAX_THREADS = %d)", GMX_OPENMP_MAX_THREADS));
 #else
-    fprintf(fp, "OpenMP support:     disabled\n");
+    writer->writeLine("OpenMP support:     disabled");
 #endif
-    fprintf(fp, "GPU support:        %s\n", getGpuImplementationString());
-    fprintf(fp, "SIMD instructions:  %s\n", GMX_SIMD_STRING);
-    fprintf(fp, "FFT library:        %s\n", getFftDescriptionString());
+    writer->writeLine(formatString("GPU support:        %s", getGpuImplementationString()));
+    writer->writeLine(formatString("SIMD instructions:  %s", GMX_SIMD_STRING));
+    writer->writeLine(formatString("FFT library:        %s", getFftDescriptionString()));
 #ifdef HAVE_RDTSCP
-    fprintf(fp, "RDTSCP usage:       enabled\n");
+    writer->writeLine("RDTSCP usage:       enabled");
 #else
-    fprintf(fp, "RDTSCP usage:       disabled\n");
+    writer->writeLine("RDTSCP usage:       disabled");
 #endif
 #ifdef GMX_USE_TNG
-    fprintf(fp, "TNG support:        enabled\n");
+    writer->writeLine("TNG support:        enabled");
 #else
-    fprintf(fp, "TNG support:        disabled\n");
+    writer->writeLine("TNG support:        disabled");
 #endif
 #if GMX_HWLOC
-    fprintf(fp, "Hwloc support:      hwloc-%d.%d.%d\n",
-            HWLOC_API_VERSION>>16,
-            (HWLOC_API_VERSION>>8) & 0xFF,
-            HWLOC_API_VERSION & 0xFF);
+    writer->writeLine(formatString("Hwloc support:      hwloc-%d.%d.%d",
+                                   HWLOC_API_VERSION>>16,
+                                   (HWLOC_API_VERSION>>8) & 0xFF,
+                                   HWLOC_API_VERSION & 0xFF));
 #else
-    fprintf(fp, "Hwloc support:      disabled\n");
+    writer->writeLine("Hwloc support:      disabled");
 #endif
 #if HAVE_EXTRAE
     unsigned major, minor, revision;
     Extrae_get_version(&major, &minor, &revision);
-    fprintf(fp, "Tracing support:    enabled. Using Extrae-%d.%d.%d\n", major, minor, revision);
+    writer->writeLine(formatString("Tracing support:    enabled. Using Extrae-%d.%d.%d", major, minor, revision));
 #else
-    fprintf(fp, "Tracing support:    disabled\n");
+    writer->writeLine("Tracing support:    disabled");
 #endif
 
 
-    fprintf(fp, "Built on:           %s\n", BUILD_TIME);
-    fprintf(fp, "Built by:           %s\n", BUILD_USER);
-    fprintf(fp, "Build OS/arch:      %s\n", BUILD_HOST);
-    fprintf(fp, "Build CPU vendor:   %s\n", BUILD_CPU_VENDOR);
-    fprintf(fp, "Build CPU brand:    %s\n", BUILD_CPU_BRAND);
-    fprintf(fp, "Build CPU family:   %d   Model: %d   Stepping: %d\n",
-            BUILD_CPU_FAMILY, BUILD_CPU_MODEL, BUILD_CPU_STEPPING);
+    writer->writeLine(formatString("Built on:           %s", BUILD_TIME));
+    writer->writeLine(formatString("Built by:           %s", BUILD_USER));
+    writer->writeLine(formatString("Build OS/arch:      %s", BUILD_HOST));
+    writer->writeLine(formatString("Build CPU vendor:   %s", BUILD_CPU_VENDOR));
+    writer->writeLine(formatString("Build CPU brand:    %s", BUILD_CPU_BRAND));
+    writer->writeLine(formatString("Build CPU family:   %d   Model: %d   Stepping: %d",
+                                   BUILD_CPU_FAMILY, BUILD_CPU_MODEL, BUILD_CPU_STEPPING));
     /* TODO: The below strings can be quite long, so it would be nice to wrap
      * them. Can wait for later, as the master branch has ready code to do all
      * that. */
-    fprintf(fp, "Build CPU features: %s\n", BUILD_CPU_FEATURES);
-    fprintf(fp, "C compiler:         %s\n", BUILD_C_COMPILER);
-    fprintf(fp, "C compiler flags:   %s\n", BUILD_CFLAGS);
-    fprintf(fp, "C++ compiler:       %s\n", BUILD_CXX_COMPILER);
-    fprintf(fp, "C++ compiler flags: %s\n", BUILD_CXXFLAGS);
+    writer->writeLine(formatString("Build CPU features: %s", BUILD_CPU_FEATURES));
+    writer->writeLine(formatString("C compiler:         %s", BUILD_C_COMPILER));
+    writer->writeLine(formatString("C compiler flags:   %s", BUILD_CFLAGS));
+    writer->writeLine(formatString("C++ compiler:       %s", BUILD_CXX_COMPILER));
+    writer->writeLine(formatString("C++ compiler flags: %s", BUILD_CXXFLAGS));
 #ifdef HAVE_LIBMKL
     /* MKL might be used for LAPACK/BLAS even if FFTs use FFTW, so keep it separate */
-    fprintf(fp, "Linked with Intel MKL version %d.%d.%d.\n",
-            __INTEL_MKL__, __INTEL_MKL_MINOR__, __INTEL_MKL_UPDATE__);
+    writer->writeLine(formatString("Linked with Intel MKL version %d.%d.%d.",
+                                   __INTEL_MKL__, __INTEL_MKL_MINOR__, __INTEL_MKL_UPDATE__));
 #endif
 #if GMX_GPU == GMX_GPU_OPENCL
-    fprintf(fp, "OpenCL include dir: %s\n", OPENCL_INCLUDE_DIR);
-    fprintf(fp, "OpenCL library:     %s\n", OPENCL_LIBRARY);
-    fprintf(fp, "OpenCL version:     %s\n", OPENCL_VERSION_STRING);
+    writer->writeLine(formatString("OpenCL include dir: %s", OPENCL_INCLUDE_DIR));
+    writer->writeLine(formatString("OpenCL library:     %s", OPENCL_LIBRARY));
+    writer->writeLine(formatString("OpenCL version:     %s", OPENCL_VERSION_STRING));
 #endif
 #if GMX_GPU == GMX_GPU_CUDA
-    gmx_print_version_info_cuda_gpu(fp);
+    writer->writeLine(formatString("CUDA compiler:      %s\n", CUDA_NVCC_COMPILER_INFO));
+    writer->writeLine(formatString("CUDA compiler flags:%s\n", CUDA_NVCC_COMPILER_FLAGS));
+    auto driverVersion = gmx::getCudaDriverVersion();
+    writer->writeLine(formatString("CUDA driver:        %d.%d\n", driverVersion.first, driverVersion.second));
+    auto runtimeVersion = gmx::getCudaRuntimeVersion();
+    writer->writeLine(formatString("CUDA runtime:       %d.%d\n", runtimeVersion.first, runtimeVersion.second));
 #endif
 }
 
@@ -323,13 +331,28 @@ BinaryInformationSettings::BinaryInformationSettings()
 void printBinaryInformation(FILE                  *fp,
                             const IProgramContext &programContext)
 {
-    printBinaryInformation(fp, programContext, BinaryInformationSettings());
+    TextWriter writer(fp);
+    printBinaryInformation(&writer, programContext, BinaryInformationSettings());
 }
 
 void printBinaryInformation(FILE                            *fp,
                             const IProgramContext           &programContext,
                             const BinaryInformationSettings &settings)
 {
+    try
+    {
+        TextWriter writer(fp);
+        printBinaryInformation(&writer, programContext, settings);
+    }
+    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+}
+
+void printBinaryInformation(TextWriter                      *writer,
+                            const IProgramContext           &programContext,
+                            const BinaryInformationSettings &settings)
+{
+    // TODO Perhaps the writer could be configured with the prefix and
+    // suffix strings from the settings?
     const char *prefix          = settings.prefix_;
     const char *suffix          = settings.suffix_;
     const char *precisionString = "";
@@ -339,7 +362,7 @@ void printBinaryInformation(FILE                            *fp,
     const char *const name = programContext.displayName();
     if (settings.bGeneratedByHeader_)
     {
-        fprintf(fp, "%sCreated by:%s\n", prefix, suffix);
+        writer->writeLine(formatString("%sCreated by:%s", prefix, suffix));
     }
     // TODO: It would be nice to know here whether we are really running a
     // Gromacs binary or some other binary that is calling Gromacs; we
@@ -348,50 +371,50 @@ void printBinaryInformation(FILE                            *fp,
         = formatString(":-) GROMACS - %s, %s%s (-:", name, gmx_version(), precisionString);
     const int   indent
         = centeringOffset(78 - std::strlen(prefix) - std::strlen(suffix), title.length()) + 1;
-    fprintf(fp, "%s%*c%s%s\n", prefix, indent, ' ', title.c_str(), suffix);
-    fprintf(fp, "%s%s\n", prefix, suffix);
+    writer->writeLine(formatString("%s%*c%s%s", prefix, indent, ' ', title.c_str(), suffix));
+    writer->writeLine(formatString("%s%s", prefix, suffix));
     if (settings.bCopyright_)
     {
         GMX_RELEASE_ASSERT(prefix[0] == '\0' && suffix[0] == '\0',
                            "Prefix/suffix not supported with copyright");
-        printCopyright(fp);
-        fprintf(fp, "\n");
+        printCopyright(writer);
+        writer->ensureEmptyLine();
         // This line is printed again after the copyright notice to make it
         // appear together with all the other information, so that it is not
         // necessary to read stuff above the copyright notice.
         // The line above the copyright notice puts the copyright notice is
         // context, though.
-        fprintf(fp, "%sGROMACS:      %s, version %s%s%s\n", prefix, name,
-                gmx_version(), precisionString, suffix);
+        writer->writeLine(formatString("%sGROMACS:      %s, version %s%s%s", prefix, name,
+                                       gmx_version(), precisionString, suffix));
     }
     const char *const binaryPath = programContext.fullBinaryPath();
     if (!gmx::isNullOrEmpty(binaryPath))
     {
-        fprintf(fp, "%sExecutable:   %s%s\n", prefix, binaryPath, suffix);
+        writer->writeLine(formatString("%sExecutable:   %s%s", prefix, binaryPath, suffix));
     }
     const gmx::InstallationPrefixInfo installPrefix = programContext.installationPrefix();
     if (!gmx::isNullOrEmpty(installPrefix.path))
     {
-        fprintf(fp, "%sData prefix:  %s%s%s\n", prefix, installPrefix.path,
-                installPrefix.bSourceLayout ? " (source tree)" : "", suffix);
+        writer->writeLine(formatString("%sData prefix:  %s%s%s", prefix, installPrefix.path,
+                                       installPrefix.bSourceLayout ? " (source tree)" : "", suffix));
     }
     const std::string workingDir = Path::getWorkingDirectory();
     if (!workingDir.empty())
     {
-        fprintf(fp, "%sWorking dir:  %s%s\n", prefix, workingDir.c_str(), suffix);
+        writer->writeLine(formatString("%sWorking dir:  %s%s", prefix, workingDir.c_str(), suffix));
     }
     const char *const commandLine = programContext.commandLine();
     if (!gmx::isNullOrEmpty(commandLine))
     {
-        fprintf(fp, "%sCommand line:%s\n%s  %s%s\n",
-                prefix, suffix, prefix, commandLine, suffix);
+        writer->writeLine(formatString("%sCommand line:%s\n%s  %s%s",
+                                       prefix, suffix, prefix, commandLine, suffix));
     }
     if (settings.bExtendedInfo_)
     {
         GMX_RELEASE_ASSERT(prefix[0] == '\0' && suffix[0] == '\0',
                            "Prefix/suffix not supported with extended info");
-        fprintf(fp, "\n");
-        gmx_print_version_info(fp);
+        writer->ensureEmptyLine();
+        gmx_print_version_info(writer);
     }
 }
 
index 4611aa79538b018b7bce2418cbfdc82ee45343a1..670f0a88bba27d55dd4e7e4129f81b57b07e9191 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -49,6 +49,7 @@ namespace gmx
 {
 
 class IProgramContext;
+class TextWriter;
 
 /*! \libinternal \brief
  * Settings for printBinaryInformation().
@@ -103,7 +104,8 @@ class BinaryInformationSettings
 
         //! Needed to read the members without otherwise unnecessary accessors.
         friend void printBinaryInformation(
-            FILE *fp, const IProgramContext &programContext,
+            TextWriter                      *writer,
+            const IProgramContext           &programContext,
             const BinaryInformationSettings &settings);
 };
 
@@ -128,6 +130,20 @@ void printBinaryInformation(FILE                            *fp,
                             const IProgramContext           &programContext,
                             const BinaryInformationSettings &settings);
 
+/*! \brief
+ * Print basic information about the executable with custom settings.
+ *
+ * \param[out] writer         Where to print the information.
+ * \param[in]  programContext Program information object to use.
+ * \param[in]  settings       Specifies what to print.
+ * \throws     std::bad_alloc if out of memory.
+ *
+ * \see BinaryInformationSettings
+ */
+void printBinaryInformation(TextWriter                      *writer,
+                            const IProgramContext           &programContext,
+                            const BinaryInformationSettings &settings);
+
 }     // namespace gmx
 
 #endif
index cdd186b1038b72660abd26e2b5602e5b84ac3868..af1d21e9de2805e520f0685bce967b4c80199cd9 100644 (file)
@@ -54,7 +54,6 @@
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/smalloc.h"
-#include "gromacs/utility/sysinfo.h"
 
 //! Comment sign to use.
 #define COMMENTSIGN ';'
@@ -182,28 +181,6 @@ void trim (char *str)
     rtrim (str);
 }
 
-void nice_header(FILE *out, const char *fn)
-{
-    int            uid;
-    char           userbuf[256];
-    char           hostbuf[256];
-    char           timebuf[STRLEN];
-
-    /* Print a nice header above the file */
-    fprintf(out, "%c\n", COMMENTSIGN);
-    fprintf(out, "%c\tFile '%s' was generated\n", COMMENTSIGN, fn ? fn : "unknown");
-
-    uid  = gmx_getuid();
-    gmx_getusername(userbuf, 256);
-    gmx_gethostname(hostbuf, 256);
-    gmx_format_current_time(timebuf, STRLEN);
-
-    fprintf(out, "%c\tBy user: %s (%d)\n", COMMENTSIGN, userbuf, uid);
-    fprintf(out, "%c\tOn host: %s\n", COMMENTSIGN, hostbuf);
-    fprintf(out, "%c\tAt date: %s\n", COMMENTSIGN, timebuf);
-    fprintf(out, "%c\n", COMMENTSIGN);
-}
-
 int gmx_strcasecmp_min(const char *str1, const char *str2)
 {
     char ch1, ch2;
index 3223951b58f1345630803ea04a3c8459cd220cb0..62e5037211633c250467883a9aeea73d24b94306 100644 (file)
@@ -90,9 +90,6 @@ void rtrim(char *str);
 /** Remove leading and trailing whitespace from a string. */
 void trim(char *str);
 
-/** Prints creation time stamp and user information into a file as comments. */
-void nice_header(FILE *out, const char *fn);
-
 /** Version of gmx_strcasecmp() that also ignores '-' and '_'. */
 int gmx_strcasecmp_min(const char *str1, const char *str2);
 /** Version of gmx_strncasecmp() that also ignores '-' and '_'. */
index 98ce1cc2ccf7fc4e0b20f5d2e53f535e50024436..0d759bb47221b3a3cbee8dc9bca5c474890e961a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2017, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 #include "cuda_version_information.h"
 
-#include <cstdio>
+#include <utility>
 
-#include "buildinfo.h"
+namespace gmx
+{
 
-void gmx_print_version_info_cuda_gpu(FILE *fp)
+std::pair<int, int> getCudaDriverVersion()
 {
-    int cuda_driver, cuda_runtime;
-    fprintf(fp, "CUDA compiler:      %s\n", CUDA_NVCC_COMPILER_INFO);
-    fprintf(fp, "CUDA compiler flags:%s\n", CUDA_NVCC_COMPILER_FLAGS);
-    cuda_driver = 0;
+    int cuda_driver;
     cudaDriverGetVersion(&cuda_driver);
-    cuda_runtime = 0;
+    return std::pair<int, int>(cuda_driver/1000, cuda_driver%100);
+}
+
+std::pair<int, int> getCudaRuntimeVersion()
+{
+    int cuda_runtime;
     cudaRuntimeGetVersion(&cuda_runtime);
-    fprintf(fp, "CUDA driver:        %d.%d\n", cuda_driver/1000, cuda_driver%100);
-    fprintf(fp, "CUDA runtime:       %d.%d\n", cuda_runtime/1000, cuda_runtime%100);
+    return std::pair<int, int>(cuda_runtime/1000, cuda_runtime%100);
 }
+
+} // namespace
index edff41ce498c51315fc4f46a227e4a27aaac3e7b..4cced2ca80e25d1475d8b816974e22a5b6a494a6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2017, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-#ifndef GMX_GMXLIB_CUDA_TOOLS_CUDA_VERSION_INFORMATION_H
-#define GMX_GMXLIB_CUDA_TOOLS_CUDA_VERSION_INFORMATION_H
+#ifndef GMX_UTILITY_CUDA_VERSION_INFORMATION_H
+#define GMX_UTILITY_CUDA_VERSION_INFORMATION_H
 
-#include <cstdio>
+#include <utility>
 
-void gmx_print_version_info_cuda_gpu(FILE *fp);
+namespace gmx
+{
+
+//! Returns a (major, minor) tuple of the CUDA driver version.
+std::pair<int, int> getCudaDriverVersion();
+
+//! Returns a (major, minor) tuple of the CUDA runtime version.
+std::pair<int, int> getCudaRuntimeVersion();
+
+} // namespace
 
 #endif
diff --git a/src/gromacs/utility/niceheader.cpp b/src/gromacs/utility/niceheader.cpp
new file mode 100644 (file)
index 0000000..d1ce031
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2017, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions from niceheader.h.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \ingroup module_utility
+ */
+#include "gmxpre.h"
+
+#include "niceheader.h"
+
+#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/sysinfo.h"
+#include "gromacs/utility/textwriter.h"
+
+namespace gmx
+{
+
+void niceHeader(TextWriter *writer, const char *fn, char commentChar)
+{
+    int            uid;
+    char           userbuf[256];
+    char           hostbuf[256];
+    char           timebuf[256];
+
+    /* Write a nice header for an output file */
+    writer->writeLine(formatString("%c", commentChar));
+    writer->writeLine(formatString("%c\tFile '%s' was generated", commentChar, fn ? fn : "unknown"));
+
+    uid  = gmx_getuid();
+    gmx_getusername(userbuf, 256);
+    gmx_gethostname(hostbuf, 256);
+    gmx_format_current_time(timebuf, 256);
+
+    writer->writeLine(formatString("%c\tBy user: %s (%d)", commentChar, userbuf, uid));
+    writer->writeLine(formatString("%c\tOn host: %s", commentChar, hostbuf));
+    writer->writeLine(formatString("%c\tAt date: %s", commentChar, timebuf));
+    writer->writeLine(formatString("%c", commentChar));
+}
+
+} // namespace
diff --git a/src/gromacs/utility/niceheader.h b/src/gromacs/utility/niceheader.h
new file mode 100644 (file)
index 0000000..fb72ca8
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2017, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares function for printing a nice header for text output files.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_NICEHEADER_H
+#define GMX_UTILITY_NICEHEADER_H
+
+namespace gmx
+{
+
+class TextWriter;
+
+/*! \brief
+ * Prints creation time stamp and user information into a string as comments, and returns it.
+ *
+ * \param[out] writer         Where to print the information.
+ * \param[in]  fn             Name of the file being written; if nullptr, described as "unknown".
+ * \param[in]  commentChar    Character to use as the starting delimiter for comments.
+ * \throws     std::bad_alloc if out of memory. */
+void niceHeader(TextWriter *writer, const char *fn, char commentChar);
+
+} // namespace
+
+#endif
index 3b3c50a40c4416b065ad87cf2bb8f5a884bdc817..fedb8bb082b024bb4381346dc3c3217ab04ec878 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014, by the GROMACS development team, led by
+ * Copyright (c) 2014,2017, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -34,8 +34,9 @@
  */
 /*! \libinternal \file
  * \brief
- * Declares functions for obtaining information about the operating environment
- * and the current process.
+ * Declares functions that wrap platform-specific calls for obtaining
+ * information about the operating environment and the current
+ * process.
  *
  * \author Teemu Murtola <teemu.murtola@gmail.com>
  * \inlibraryapi
 #include <stddef.h>
 #include <time.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*! \addtogroup module_utility
  * \{
  */
@@ -117,8 +114,4 @@ int gmx_set_nice(int level);
 
 /*! \} */
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
index 1d28534ed64118a0ad7f03d84cf3c15a61f05f08..4a71a749f0dde724cb538fe5c725d3f8b145611d 100644 (file)
@@ -223,9 +223,11 @@ static void get_input(const char *membed_input, real *xy_fac, real *xy_max, real
 
     wi = init_warning(TRUE, 0);
 
-    gmx::TextInputFile stream(membed_input);
-    inp = read_inpfile(&stream, membed_input, &ninp, wi);
-
+    {
+        gmx::TextInputFile stream(membed_input);
+        inp = read_inpfile(&stream, membed_input, &ninp, wi);
+        stream.close();
+    }
     ITYPE ("nxy", *it_xy, 1000);
     ITYPE ("nz", *it_z, 0);
     RTYPE ("xyinit", *xy_fac, 0.5);
@@ -237,8 +239,13 @@ static void get_input(const char *membed_input, real *xy_fac, real *xy_max, real
     ITYPE ("maxwarn", *maxwarn, 0);
     ITYPE ("pieces", *pieces, 1);
     EETYPE("asymmetry", *bALLOW_ASYMMETRY, yesno_names);
+
     check_warning_error(wi, FARGS);
-    write_inpfile(membed_input, ninp, inp, FALSE, WriteMdpHeader::yes, wi);
+    {
+        gmx::TextOutputFile stream(membed_input);
+        write_inpfile(&stream, membed_input, ninp, inp, FALSE, WriteMdpHeader::yes, wi);
+        stream.close();
+    }
     done_warning(wi, FARGS);
 }