Markup substitution through HelpWriterContext.
authorTeemu Murtola <teemu.murtola@gmail.com>
Tue, 17 Sep 2013 17:49:12 +0000 (20:49 +0300)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Wed, 30 Oct 2013 15:45:11 +0000 (16:45 +0100)
Make all calls to process the in-source strings to help output go
through HelpWriterContext.  This makes it easy to implement common
functionality using C++ mechanisms.

Moved all the HTML link processing stuff into HelpWriterContext as well
and cleaned up links.dat.  The generated HTML pages should no longer
contain broken links (but links between program pages are not there
yet).

The markup substitution itself is still done by functions in wman.cpp;
will move those into private functions in helpwritercontext.cpp as a
separate change.

Related to #685 and #969.

Change-Id: I37d45549214e49a6edab82fb64ec7b38b9e72094

13 files changed:
share/top/links.dat
src/gromacs/commandline/cmdlinehelpcontext.cpp
src/gromacs/commandline/cmdlinehelpcontext.h
src/gromacs/commandline/cmdlinemodulemanager.cpp
src/gromacs/onlinehelp/helpwritercontext.cpp
src/gromacs/onlinehelp/helpwritercontext.h
src/gromacs/onlinehelp/wman.cpp
src/gromacs/onlinehelp/wman.h
src/gromacs/selection/selectioncollection.cpp
src/gromacs/utility/file.cpp
src/gromacs/utility/file.h
src/gromacs/utility/stringutil.cpp
src/gromacs/utility/stringutil.h

index 443f1f9f2453562a17e71f1aa2cb942adec29247..b70980b494456539f8a508c15ac8c37c4d808277 100644 (file)
@@ -1,99 +1,30 @@
+cpt
 dat
 dlg
-do_dssp
 edi
-editconf
 edo
 edr
 ene
-eneconv
 eps
 g87
 g96
-g_anaeig
-g_analyze
-g_angle
-g_bond
-g_bundle
-g_chi
-g_cluster
-g_confrms
-g_coord
-g_covar
-g_density
-g_dielectric
-g_dipoles
-g_disre
-g_dist
-g_dyndom
-g_enemat
-g_energy
-g_filter
-g_gyrate
-g_h2order
-g_hbond
-g_helix
-g_mdmat
-g_mindist
-g_morph
-g_msd
-g_nmeig
-g_nmens
-g_order
-g_potential
-g_rama
-g_rdf
-g_rms
-g_rmsdist
-g_rmsf
-g_rotacf
-g_saltbr
-g_sas
-g_sgangle
-g_sorient
-g_tcaf
-g_traj
-g_velacc
-genbox
-genconf
-gendr
-genion
-genpr
-gmxcheck
-gmxdump
 gro
-grompp
 hdb
-highway
 itp
 m2p
-make_ndx
 mdp
-mdrun
-mk_angndx
 mtx
 ndx
-ngmx
 pdb
-pdb2gmx
-protonate
 rtp
 tex
 top
 tpa
 tpb
-tpbconv
 tpr
 trj
-trjcat
-trjconv
-trjorder
 trr
-wheel
-x2top
 xpm
-xpm2ps
-xrama
 xtc
 xvg
 map
index 4ead26902fdb77aaf6ff55aefc9d0cc6caa9720f..9085c5626a44ad4b6573543b81491e8f52fbef27 100644 (file)
@@ -99,6 +99,10 @@ void CommandLineHelpContext::setModuleDisplayName(const std::string &name)
     impl_->moduleDisplayName_ = name;
 }
 
+void CommandLineHelpContext::setLinks(const HelpLinks &links)
+{
+    impl_->writerContext_.setLinks(links);
+}
 
 void CommandLineHelpContext::setShowHidden(bool bHidden)
 {
index db1d78bf096cfb3f2fe50f2e2bb6cf871cdcefb0..9e12f4a1d46769eb633b98102a97d5c44fc868fa 100644 (file)
@@ -76,6 +76,14 @@ class CommandLineHelpContext
          * \throws std::bad_alloc if out of memory.
          */
         void setModuleDisplayName(const std::string &name);
+        /*! \brief
+         * Sets the links to process in help output.
+         *
+         * A reference to \p links is stored until the CommandLineHelpContext
+         * is destructed.  The caller is responsible for ensuring that the
+         * links object remains valid long enough.
+         */
+        void setLinks(const HelpLinks &links);
         //! Sets whether hidden options should be shown in help output.
         void setShowHidden(bool bHidden);
 
index f6dbbbbc53c7d1d9549c7a6ecb13cf3608142e2a..3486a1e48cd0379371e43fb9f330a1d9ecea7379 100644 (file)
 
 #include "gromacs/legacyheaders/copyrite.h"
 #include "gromacs/legacyheaders/network.h"
+#include "gromacs/legacyheaders/smalloc.h"
 
 #include "gromacs/commandline/cmdlinehelpcontext.h"
 #include "gromacs/commandline/cmdlinemodule.h"
 #include "gromacs/commandline/cmdlineparser.h"
+#include "gromacs/fileio/futil.h"
 #include "gromacs/onlinehelp/helpformat.h"
 #include "gromacs/onlinehelp/helpmanager.h"
 #include "gromacs/onlinehelp/helptopic.h"
@@ -326,6 +328,8 @@ void HelpExportMan::exportModuleHelp(const std::string                &tag,
 class HelpExportHtml : public HelpExportInterface
 {
     public:
+        HelpExportHtml();
+
         virtual void startModuleExport();
         virtual void exportModuleHelp(const std::string                &tag,
                                       const CommandLineModuleInterface &module);
@@ -336,8 +340,24 @@ class HelpExportHtml : public HelpExportInterface
         void writeHtmlFooter(File *file) const;
 
         boost::scoped_ptr<File>  byNameFile_;
+        HelpLinks                links_;
 };
 
+HelpExportHtml::HelpExportHtml()
+{
+    char *linksFilename = low_gmxlibfn("links.dat", FALSE, FALSE);
+    if (linksFilename != NULL)
+    {
+        scoped_ptr_sfree guard(linksFilename);
+        File             linksFile(linksFilename, "r");
+        std::string      line;
+        while (linksFile.readLine(&line))
+        {
+            links_.addLink(line, "../online/" + line);
+        }
+    }
+}
+
 void HelpExportHtml::startModuleExport()
 {
     byNameFile_.reset(new File("byname.html", "w"));
@@ -355,6 +375,7 @@ void HelpExportHtml::exportModuleHelp(const std::string                &tag,
     std::string            displayName(tag);
     std::replace(displayName.begin(), displayName.end(), '-', ' ');
     context.setModuleDisplayName(displayName);
+    context.setLinks(links_);
     module.writeHelp(context);
 
     writeHtmlFooter(&file);
index db85fcbd773ead68ba9324584a7e9720476844f1..08239d30db423d3d710621fa2b577c7780349b12 100644 (file)
@@ -167,6 +167,54 @@ std::string toUpperCase(const std::string &text)
 
 }   // namespace
 
+/********************************************************************
+ * HelpLinks::Impl
+ */
+
+/*! \internal \brief
+ * Private implementation class for HelpLinks.
+ *
+ * \ingroup module_onlinehelp
+ */
+class HelpLinks::Impl
+{
+    public:
+        struct LinkItem
+        {
+            LinkItem(const std::string &linkName,
+                     const std::string &targetName)
+                : linkName(linkName), targetName(targetName)
+            {
+            }
+            std::string         linkName;
+            std::string         targetName;
+        };
+
+        //! Shorthand for a list of links.
+        typedef std::vector<LinkItem> LinkList;
+
+        //! List of links.
+        LinkList        links_;
+};
+
+/********************************************************************
+ * HelpLinks
+ */
+
+HelpLinks::HelpLinks() : impl_(new Impl)
+{
+}
+
+HelpLinks::~HelpLinks()
+{
+}
+
+void HelpLinks::addLink(const std::string &linkName,
+                        const std::string &targetName)
+{
+    impl_->links_.push_back(Impl::LinkItem(linkName, targetName));
+}
+
 /********************************************************************
  * HelpWriterContext::Impl
  */
@@ -181,7 +229,7 @@ class HelpWriterContext::Impl
     public:
         //! Initializes the context with the given output file and format.
         explicit Impl(File *file, HelpOutputFormat format)
-            : file_(*file), format_(format)
+            : file_(*file), format_(format), links_(NULL)
         {
         }
 
@@ -201,6 +249,8 @@ class HelpWriterContext::Impl
         File                   &file_;
         //! Output format for the help output.
         HelpOutputFormat        format_;
+        //! Links to use.
+        const HelpLinks        *links_;
 };
 
 void HelpWriterContext::Impl::processMarkup(const std::string &text,
@@ -224,6 +274,37 @@ void HelpWriterContext::Impl::processMarkup(const std::string &text,
             }
             return wrapper->wrap(result);
         }
+        case eHelpOutputFormat_Man:
+        {
+            {
+                char            *resultStr = check_nroff(result.c_str());
+                scoped_ptr_sfree resultGuard(resultStr);
+                result = resultStr;
+            }
+            return wrapper->wrap(result);
+        }
+        case eHelpOutputFormat_Html:
+        {
+            {
+                char            *resultStr = check_html(result.c_str());
+                scoped_ptr_sfree resultGuard(resultStr);
+                result = resultStr;
+            }
+            if (links_ != NULL)
+            {
+                HelpLinks::Impl::LinkList::const_iterator link;
+                for (link  = links_->impl_->links_.begin();
+                     link != links_->impl_->links_.end(); ++link)
+                {
+                    std::string replacement
+                        = formatString("<a href=\"%s.html\">%s</a>",
+                                       link->targetName.c_str(),
+                                       link->linkName.c_str());
+                    result = replaceAllWords(result, link->linkName, replacement);
+                }
+            }
+            return wrapper->wrap(result);
+        }
         default:
             GMX_THROW(InternalError("Invalid help output format"));
     }
@@ -242,6 +323,11 @@ HelpWriterContext::~HelpWriterContext()
 {
 }
 
+void HelpWriterContext::setLinks(const HelpLinks &links)
+{
+    impl_->links_ = &links;
+}
+
 HelpOutputFormat HelpWriterContext::outputFormat() const
 {
     return impl_->format_;
index d2ea44daef7417ff28462a5c81248182ad661bef..20ed1f49ab83293163c3d4ffabb183d3e0c56c0c 100644 (file)
@@ -65,6 +65,45 @@ enum HelpOutputFormat
 };
 //! \endcond
 
+/*! \libinternal \brief
+ * Hyperlink data for writing out help.
+ *
+ * This class is separate from HelpWriterContext to allow constructing the list
+ * of links once and reusing them across multiple help writer contexts.
+ * This is used when exporting all the help from the wrapper binary to avoid
+ * repeatedly constructing the same data structure for each help item.
+ *
+ * \ingroup module_onlinehelp
+ */
+class HelpLinks
+{
+    public:
+        //! Initializes an empty links collection.
+        HelpLinks();
+        ~HelpLinks();
+
+        /*! \brief
+         * Adds a link.
+         *
+         * \param[in] linkName   Name of the link in input text.
+         * \param[in] targetName Hyperlink target.
+         *
+         * Any occurrence of \p linkName in the text passed to markup
+         * substitution methods in HelpWriterContext is made into a hyperlink
+         * to \p targetName if the markup format supports that.
+         */
+        void addLink(const std::string &linkName,
+                     const std::string &targetName);
+
+    private:
+        class Impl;
+
+        PrivateImplPointer<Impl> impl_;
+
+        //! Allows the context to use the links.
+        friend class HelpWriterContext;
+};
+
 /*! \libinternal \brief
  * Context information for writing out help.
  *
@@ -91,6 +130,9 @@ class HelpWriterContext
         HelpWriterContext(File *file, HelpOutputFormat format);
         ~HelpWriterContext();
 
+        //! Sets the links to use in this context.
+        void setLinks(const HelpLinks &links);
+
         /*! \brief
          * Returns the active output format.
          *
index 0967a0331cb9f12f54e11355dbbf427252fe439a..5979b185bdfaf76213350a801288b848993f3637 100644 (file)
  * And Hey:
  * GROningen Mixture of Alchemy and Childrens' Stories
  */
+#include <cstdio>
+#include <cstring>
+
 #include <string>
 
 #include "gromacs/commandline/cmdlinehelpcontext.h"
+#include "gromacs/fileio/filenm.h"
+#include "gromacs/fileio/gmxfio.h"
 #include "gromacs/onlinehelp/wman.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/file.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/stringutil.h"
 
-#include "gmx_fatal.h"
 #include "string2.h"
 #include "smalloc.h"
-#include "sysstuff.h"
-#include "gromacs/fileio/filenm.h"
-#include "gromacs/fileio/gmxfio.h"
 #include "macros.h"
 #include "statutil.h"
-#include "copyrite.h"
-#include "strdb.h"
 #include "readinp.h"
 
 /* The source code in this file should be thread-safe.
 
 typedef struct {
     const char *search, *replace;
-} t_sandr_const;
-
-typedef struct {
-    char *search, *replace;
 } t_sandr;
 
 /* The order of these arrays is significant. Text search and replace
@@ -69,7 +65,7 @@ typedef struct {
  * subsequent changes even though the original text might not appear
  * to invoke the latter changes. */
 
-const t_sandr_const sandrTty[] = {
+const t_sandr sandrTty[] = {
     { "[TT]", "" },
     { "[tt]", "" },
     { "[BB]", "" },
@@ -119,7 +115,7 @@ const t_sandr_const sandrTty[] = {
 };
 #define NSRTTY asize(sandrTty)
 
-const t_sandr_const sandrNROFF[] = {
+const t_sandr sandrNROFF[] = {
     { "[TT]", "\\fB " },
     { "[tt]", "\\fR" },
     { "[BB]", "\\fB " },
@@ -175,7 +171,7 @@ const t_sandr_const sandrNROFF[] = {
 };
 #define NSRNROFF asize(sandrNROFF)
 
-const t_sandr_const sandrHTML[] = {
+const t_sandr sandrHTML[] = {
     { "<",    "&lt;" },
     { ">",    "&gt;" },
     { "[TT]", "<tt>" },
@@ -227,37 +223,7 @@ const t_sandr_const sandrHTML[] = {
 };
 #define NSRHTML asize(sandrHTML)
 
-
-/* Data structure for saved HTML links */
-typedef struct t_linkdata {
-    int      nsr;
-    t_sandr *sr;
-} t_linkdata;
-
-static t_linkdata *init_linkdata()
-{
-    t_linkdata *p;
-    snew(p, 1);
-    p->sr  = NULL;
-    p->nsr = 0;
-
-    return p;
-}
-
-static void finish_linkdata(t_linkdata *p)
-{
-    int i;
-
-    for (i = 0; i < p->nsr; i++)
-    {
-        sfree(p->sr[i].search);
-        sfree(p->sr[i].replace);
-    }
-    sfree(p->sr);
-    sfree(p);
-}
-
-static char *repall(const char *s, int nsr, const t_sandr_const sa[])
+static char *repall(const char *s, int nsr, const t_sandr sa[])
 {
     try
     {
@@ -271,67 +237,21 @@ static char *repall(const char *s, int nsr, const t_sandr_const sa[])
     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
 }
 
-static char *repallww(const char *s, int nsr, const t_sandr sa[])
-{
-    try
-    {
-        std::string result(s);
-        for (int i = 0; i < nsr; ++i)
-        {
-            result = gmx::replaceAllWords(result, sa[i].search, sa[i].replace);
-        }
-        return gmx_strdup(result.c_str());
-    }
-    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
-}
-
-static char *html_xref(char *s, const char *program, t_linkdata *links)
+char *check_nroff(const char *s)
 {
-    char   buf[256], **filestr;
-    int    i, j, n;
-
-    if (links->sr == NULL)
-    {
-        n          = get_file("links.dat", &(filestr));
-        links->nsr = n;
-        snew(links->sr, n);
-        for (i = 0, j = 0; (i < n); i++)
-        {
-            if (!program || (gmx_strcasecmp(program, filestr[i])  != 0))
-            {
-                links->sr[j].search = gmx_strdup(filestr[i]);
-                sprintf(buf, "<a href=\"%s.html\">%s</a>", filestr[i], filestr[i]);
-                links->sr[j].replace = gmx_strdup(buf);
-                j++;
-            }
-        }
-        links->nsr = j;
-        for (i = 0; i < n; i++)
-        {
-            sfree(filestr[i]);
-        }
-        sfree(filestr);
-    }
-    return repallww(s, links->nsr, links->sr);
+    return repall(s, NSRNROFF, sandrNROFF);
 }
 
-static char *check_nroff(const char *s)
+char *check_html(const char *s)
 {
-    return repall(s, NSRNROFF, sandrNROFF);
+    return repall(s, NSRHTML, sandrHTML);
 }
 
-static char *check_html(const char *s, const char *program, t_linkdata *links)
+std::string check(const char *s, const gmx::HelpWriterContext &context)
 {
-    char *buf;
-
-    buf = repall(s, NSRHTML, sandrHTML);
-    buf = html_xref(buf, program, links);
-
-    return buf;
+    return context.substituteMarkupAndWrapToString(gmx::TextLineWrapperSettings(), s);
 }
 
-#define NSR(s) check_html(s, program, links)
-
 #define FLAG_SET(flag, mask) ((flag &mask) == mask)
 char *fileopt(unsigned long flag, char buf[], int maxsize)
 {
@@ -386,8 +306,7 @@ static void write_nroffman(FILE *out,
                            int nfile, t_filenm *fnm,
                            int npargs, t_pargs *pa,
                            int nbug, const char **bugs,
-                           t_linkdata *links)
-
+                           const gmx::HelpWriterContext &context)
 {
     int  i;
     char tmp[256];
@@ -400,8 +319,9 @@ static void write_nroffman(FILE *out,
     {
         for (i = 0; (i < nfile); i++)
         {
-            fprintf(out, ".BI \"%s\" \" %s \"\n", check_nroff(fnm[i].opt),
-                    check_nroff(fnm[i].fns[0]));
+            fprintf(out, ".BI \"%s\" \" %s \"\n",
+                    check(fnm[i].opt, context).c_str(),
+                    check(fnm[i].fns[0], context).c_str());
         }
     }
     if (npargs > 0)
@@ -410,12 +330,14 @@ static void write_nroffman(FILE *out,
         {
             if (pa[i].type == etBOOL)
             {
-                fprintf(out, ".BI \"\\-[no]%s\" \"\"\n", check_nroff(pa[i].option+1));
+                fprintf(out, ".BI \"\\-[no]%s\" \"\"\n",
+                        check(pa[i].option+1, context).c_str());
             }
             else
             {
-                fprintf(out, ".BI \"%s\" \" %s \"\n", check_nroff(pa[i].option),
-                        check_nroff(get_arg_desc(pa[i].type)));
+                fprintf(out, ".BI \"%s\" \" %s \"\n",
+                        check(pa[i].option, context).c_str(),
+                        check(get_arg_desc(pa[i].type), context).c_str());
             }
         }
     }
@@ -426,7 +348,7 @@ static void write_nroffman(FILE *out,
         fprintf(out, ".SH DESCRIPTION\n");
         for (i = 0; (i < nldesc); i++)
         {
-            fprintf(out, "\\&%s\n", check_nroff(desc[i]));
+            fprintf(out, "\\&%s\n", check(desc[i], context).c_str());
         }
     }
 
@@ -437,10 +359,10 @@ static void write_nroffman(FILE *out,
         for (i = 0; (i < nfile); i++)
         {
             fprintf(out, ".BI \"%s\" \" %s\" \n.B %s\n %s \n\n",
-                    check_nroff(fnm[i].opt),
-                    check_nroff(fnm[i].fns[0]),
-                    check_nroff(fileopt(fnm[i].flag, tmp, 255)),
-                    check_nroff(ftp2desc(fnm[i].ftp)));
+                    check(fnm[i].opt, context).c_str(),
+                    check(fnm[i].fns[0], context).c_str(),
+                    check(fileopt(fnm[i].flag, tmp, 255), context).c_str(),
+                    check(ftp2desc(fnm[i].ftp), context).c_str());
         }
     }
 
@@ -453,17 +375,17 @@ static void write_nroffman(FILE *out,
             if (pa[i].type == etBOOL)
             {
                 fprintf(out, ".BI \"\\-[no]%s\"  \"%s\"\n %s\n\n",
-                        check_nroff(pa[i].option+1),
-                        check_nroff(pa_val(&(pa[i]), tmp, 255)),
-                        check_nroff(pa[i].desc));
+                        check(pa[i].option+1, context).c_str(),
+                        check(pa_val(&(pa[i]), tmp, 255), context).c_str(),
+                        check(pa[i].desc, context).c_str());
             }
             else
             {
                 fprintf(out, ".BI \"%s\"  \" %s\" \" %s\" \n %s\n\n",
-                        check_nroff(pa[i].option),
-                        check_nroff(get_arg_desc(pa[i].type)),
-                        check_nroff(pa_val(&(pa[i]), tmp, 255)),
-                        check_nroff(pa[i].desc));
+                        check(pa[i].option, context).c_str(),
+                        check(get_arg_desc(pa[i].type), context).c_str(),
+                        check(pa_val(&(pa[i]), tmp, 255), context).c_str(),
+                        check(pa[i].desc, context).c_str());
             }
         }
     }
@@ -473,7 +395,7 @@ static void write_nroffman(FILE *out,
         fprintf(out, ".SH KNOWN PROBLEMS\n");
         for (i = 0; (i < nbug); i++)
         {
-            fprintf(out, "\\- %s\n\n", check_nroff(bugs[i]));
+            fprintf(out, "\\- %s\n\n", check(bugs[i], context).c_str());
         }
     }
 }
@@ -484,11 +406,10 @@ char *check_tty(const char *s)
 }
 
 static void
-print_tty_formatted(FILE *out, int nldesc, const char **desc, int indent,
-                    t_linkdata *links, const char *program)
+print_tty_formatted(FILE *out, int nldesc, const char **desc,
+                    const gmx::HelpWriterContext &context)
 {
     char *buf;
-    char *temp;
     int   buflen, i;
 
     buflen = 80*nldesc;
@@ -500,29 +421,27 @@ print_tty_formatted(FILE *out, int nldesc, const char **desc, int indent,
         {
             strcat(buf, " ");
         }
-        temp = check_tty(desc[i]);
-        if (strlen(buf) + strlen(temp) >= (size_t)(buflen-2))
+        std::string temp = check(desc[i], context);
+        if (strlen(buf) + temp.length() >= (size_t)(buflen-2))
         {
-            buflen += strlen(temp);
+            buflen += temp.length();
             srenew(buf, buflen);
         }
-        strcat(buf, temp);
-        sfree(temp);
+        strcat(buf, temp.c_str());
     }
     /* Make lines of at most 79 characters */
-    temp = wrap_lines(buf, 78, indent, FALSE);
+    char *temp = wrap_lines(buf, 78, 0, FALSE);
     fprintf(out, "%s\n", temp);
     sfree(temp);
     sfree(buf);
 }
 
 static void write_ttyman(FILE *out,
-                         const char *program,
                          int nldesc, const char **desc,
                          int nfile, t_filenm *fnm,
                          int npargs, t_pargs *pa,
                          int nbug, const char **bugs,
-                         t_linkdata *links)
+                         const gmx::HelpWriterContext &context)
 {
     int   i;
     char *tmp;
@@ -530,7 +449,7 @@ static void write_ttyman(FILE *out,
     if (nldesc > 0)
     {
         fprintf(out, "DESCRIPTION\n-----------\n");
-        print_tty_formatted(out, nldesc, desc, 0, links, program);
+        print_tty_formatted(out, nldesc, desc, context);
     }
     if (nbug > 0)
     {
@@ -540,7 +459,7 @@ static void write_ttyman(FILE *out,
         {
             snew(tmp, strlen(bugs[i])+3);
             strcpy(tmp, "* ");
-            strcpy(tmp+2, check_tty(bugs[i]));
+            strcpy(tmp+2, check(bugs[i], context).c_str());
             fprintf(out, "%s\n", wrap_lines(tmp, 78, 2, FALSE));
             sfree(tmp);
         }
@@ -557,7 +476,7 @@ static void write_ttyman(FILE *out,
 }
 
 static void pr_html_files(FILE *out, int nfile, t_filenm fnm[],
-                          const char *program, t_linkdata *links)
+                          const gmx::HelpWriterContext &context)
 {
     int  i;
     char link[10], tmp[255];
@@ -586,19 +505,18 @@ static void pr_html_files(FILE *out, int nfile, t_filenm fnm[],
                 "<TD> %s </TD>"
                 "</TR>\n",
                 fnm[i].opt, link, fnm[i].fns[0], fileopt(fnm[i].flag, tmp, 255),
-                NSR(ftp2desc(fnm[i].ftp)));
+                check(ftp2desc(fnm[i].ftp), context).c_str());
     }
 
     fprintf(out, "</TABLE>\n");
 }
 
 static void write_htmlman(FILE *out,
-                          const char *program,
                           int nldesc, const char **desc,
                           int nfile, t_filenm *fnm,
                           int npargs, t_pargs *pa,
                           int nbug, const char **bugs,
-                          t_linkdata *links)
+                          const gmx::HelpWriterContext &context)
 {
     int  i;
     char tmp[255];
@@ -608,14 +526,14 @@ static void write_htmlman(FILE *out,
         fprintf(out, "<H3>Description</H3>\n<p>\n");
         for (i = 0; (i < nldesc); i++)
         {
-            fprintf(out, "%s\n", NSR(desc[i]));
+            fprintf(out, "%s\n", check(desc[i], context).c_str());
         }
     }
     if (nfile > 0)
     {
         fprintf(out, "<P>\n");
         fprintf(out, "<H3>Files</H3>\n");
-        pr_html_files(out, nfile, fnm, program, links);
+        pr_html_files(out, nfile, fnm, context);
     }
     if (npargs > 0)
     {
@@ -639,7 +557,8 @@ static void write_htmlman(FILE *out,
                     "<TD> %s </TD>"
                     "</TD>\n",
                     (pa[i].type == etBOOL) ? "-[no]" : "-", pa[i].option+1,
-                    get_arg_desc(pa[i].type), pa_val(&(pa[i]), tmp, 255), NSR(pa[i].desc));
+                    get_arg_desc(pa[i].type), pa_val(&(pa[i]), tmp, 255),
+                    check(pa[i].desc, context).c_str());
         }
         fprintf(out, "</TABLE>\n");
     }
@@ -650,7 +569,7 @@ static void write_htmlman(FILE *out,
         fprintf(out, "<UL>\n");
         for (i = 0; (i < nbug); i++)
         {
-            fprintf(out, "<LI>%s\n", NSR(bugs[i]));
+            fprintf(out, "<LI>%s\n", check(bugs[i], context).c_str());
         }
         fprintf(out, "</UL>\n");
     }
@@ -777,10 +696,6 @@ void write_man(const char *mantp,
     int         npar;
     t_pargs    *par;
 
-    t_linkdata *links;
-
-    links = init_linkdata();
-
     const gmx::CommandLineHelpContext *context
         = gmx::GlobalCommandLineHelpContext::get();
     bool  bFileOpened = false;
@@ -819,16 +734,25 @@ void write_man(const char *mantp,
 
     if (strcmp(mantp, "nroff") == 0)
     {
+        GMX_RELEASE_ASSERT(context != NULL,
+                           "Man page export only implemented with the new context");
         write_nroffman(out, context->moduleDisplayName(), nldesc, desc,
-                       nfile, fnm, npar, par, nbug, bugs, links);
+                       nfile, fnm, npar, par, nbug, bugs,
+                       context->writerContext());
     }
     if (strcmp(mantp, "help") == 0)
     {
-        write_ttyman(out, program, nldesc, desc, nfile, fnm, npar, par, nbug, bugs, links);
+        GMX_RELEASE_ASSERT(context != NULL,
+                           "Help export only implemented with the new context");
+        write_ttyman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
+                     context->writerContext());
     }
     if (strcmp(mantp, "html") == 0)
     {
-        write_htmlman(out, program, nldesc, desc, nfile, fnm, npar, par, nbug, bugs, links);
+        GMX_RELEASE_ASSERT(context != NULL,
+                           "HTML export only implemented with the new context");
+        write_htmlman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
+                      context->writerContext());
     }
     if (strcmp(mantp, "completion-zsh") == 0)
     {
@@ -852,8 +776,6 @@ void write_man(const char *mantp,
     {
         sfree(par);
     }
-
-    finish_linkdata(links);
 }
 
 const char *get_arg_desc(int type)
index bd10a7c901501517cdf37989acdd09736e2eeb09..d87997b2c5dc670d58c6f112d4ede24e1cb58bd4 100644 (file)
@@ -56,6 +56,8 @@ char *fileopt(unsigned long flag, char buf[], int maxsize);
  * a pointer to this buffer.
  */
 
+char *check_nroff(const char *s);
+char *check_html(const char *s);
 char *check_tty(const char *s);
 
 #ifdef __cplusplus
index 62865880f6326d57dbfd2221288d2925fe2c6e28..26237dab6b597a64e586e7b211b9f277c2a22ad8 100644 (file)
@@ -136,7 +136,7 @@ bool promptLine(File *infile, bool bInteractive, std::string *line)
     {
         fprintf(stderr, "> ");
     }
-    if (!infile->readLine(line))
+    if (!infile->readLineWithTrailingSpace(line))
     {
         return false;
     }
@@ -150,7 +150,7 @@ bool promptLine(File *infile, bool bInteractive, std::string *line)
         std::string buffer;
         // Return value ignored, buffer remains empty and works correctly
         // if there is nothing to read.
-        infile->readLine(&buffer);
+        infile->readLineWithTrailingSpace(&buffer);
         line->append(buffer);
     }
     if (endsWith(*line, "\n"))
index ee2f7eee3327e4b9da8c3b4777dd8e20fbf4af98..df080911817df533f677537e422d8ef97835f198 100644 (file)
@@ -189,6 +189,20 @@ void File::readBytes(void *buffer, size_t bytes)
 }
 
 bool File::readLine(std::string *line)
+{
+    if (!readLineWithTrailingSpace(line))
+    {
+        return false;
+    }
+    size_t endPos = line->find_last_not_of(" \t\r\n");
+    if (endPos != std::string::npos)
+    {
+        line->resize(endPos + 1);
+    }
+    return true;
+}
+
+bool File::readLineWithTrailingSpace(std::string *line)
 {
     line->clear();
     const size_t bufsize = 256;
index 675c880ad90bfd2b5e29cbb48bf9681615bd7a1d..f676ea9cc2affe31ed7334c43ab204b403e3a81c 100644 (file)
@@ -133,8 +133,7 @@ class File
          * \throws     FileIOError on any I/O error.
          *
          * On error or when false is returned, \p line will be empty.
-         * Terminating newline will be present in \p line if it was present in
-         * the file.
+         * Trailing space will be removed from the line.
          * To loop over all lines in the file, use:
          * \code
            std::string line;
@@ -145,6 +144,21 @@ class File
            \endcode
          */
         bool readLine(std::string *line);
+        /*! \brief
+         * Reads a single line from the file.
+         *
+         * \param[out] line    String to receive the line.
+         * \returns    false if nothing was read because the file ended.
+         * \throws     std::bad_alloc if out of memory.
+         * \throws     FileIOError on any I/O error.
+         *
+         * On error or when false is returned, \p line will be empty.
+         * Works as readLine(), except that terminating newline will be present
+         * in \p line if it was present in the file.
+         *
+         * \see readLine()
+         */
+        bool readLineWithTrailingSpace(std::string *line);
 
         /*! \brief
          * Writes a string to the file.
index c2ae4814ffc469f8312b3ac249319fd331ba267f..ed0e77ff535c8276a8ea829dfcc1d1443f10e62a 100644 (file)
@@ -187,12 +187,26 @@ replaceAll(const std::string &input, const char *from, const char *to)
     return replaceInternal(input, from, to, false);
 }
 
+std::string
+replaceAll(const std::string &input, const std::string &from,
+           const std::string &to)
+{
+    return replaceInternal(input, from.c_str(), to.c_str(), false);
+}
+
 std::string
 replaceAllWords(const std::string &input, const char *from, const char *to)
 {
     return replaceInternal(input, from, to, true);
 }
 
+std::string
+replaceAllWords(const std::string &input, const std::string &from,
+                const std::string &to)
+{
+    return replaceInternal(input, from.c_str(), to.c_str(), true);
+}
+
 
 /********************************************************************
  * TextLineWrapperSettings
index 1665f9a5f19425dbad5d53ea1ae26117361c1474..ce0cf049a27e086385dc331b063b04c33ac17e36 100644 (file)
@@ -160,6 +160,9 @@ std::string concatenateStrings(const char * const (&sarray)[count])
  */
 std::string replaceAll(const std::string &input,
                        const char *from, const char *to);
+//! \copydoc replaceAll(const std::string &, const char *, const char *)
+std::string replaceAll(const std::string &input,
+                       const std::string &from, const std::string &to);
 /*! \brief
  * Replace whole words with others.
  *
@@ -176,6 +179,9 @@ std::string replaceAll(const std::string &input,
  */
 std::string replaceAllWords(const std::string &input,
                             const char *from, const char *to);
+//! \copydoc replaceAllWords(const std::string &, const char *, const char *)
+std::string replaceAllWords(const std::string &input,
+                            const std::string &from, const std::string &to);
 
 class TextLineWrapper;