2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2012,2013, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
37 #include "gromacs/commandline/wman.h"
44 #include "gromacs/commandline/cmdlinehelpcontext.h"
45 #include "gromacs/fileio/filenm.h"
46 #include "gromacs/utility/exceptions.h"
47 #include "gromacs/utility/file.h"
48 #include "gromacs/utility/gmxassert.h"
49 #include "gromacs/utility/stringutil.h"
51 #include "gmx_fatal.h"
55 /* The source code in this file should be thread-safe.
56 * Please keep it that way. */
58 static std::string check(const char *s, const gmx::HelpWriterContext &context)
60 return context.substituteMarkupAndWrapToString(gmx::TextLineWrapperSettings(), s);
63 static std::string check(const char *s, const gmx::CommandLineHelpContext &context)
65 return check(s, context.writerContext());
68 #define FLAG_SET(flag, mask) ((flag &mask) == mask)
69 /* Return a string describing the file type in flag.
70 * flag should the flag field of a filenm struct.
71 * You have to provide a buffer and buffer length in which
72 * the result will be written. The returned pointer is just
73 * a pointer to this buffer.
75 static char *fileopt(unsigned long flag, char buf[])
79 if (FLAG_SET(flag, ffRW))
81 sprintf(tmp, "In/Out");
83 else if (FLAG_SET(flag, ffREAD))
85 sprintf(tmp, "Input");
87 else if (FLAG_SET(flag, ffWRITE))
89 sprintf(tmp, "Output");
93 sprintf(tmp, "Dunno");
96 if (FLAG_SET(flag, ffOPT))
99 if (FLAG_SET(flag, ffSET))
108 if (FLAG_SET(flag, ffLIB))
110 strcat(tmp, ", Lib.");
112 if (FLAG_SET(flag, ffMULT))
114 strcat(tmp, ", Mult.");
117 sprintf(buf, "%s", tmp);
124 static void pr_fns(FILE *fp, int nf, const t_filenm tfn[])
128 char buf[256], *wbuf, opt_buf[32];
130 fprintf(fp, "%6s %12s %-12s %s\n", "Option", "Filename", "Type",
133 "------------------------------------------------------------\n");
134 for (i = 0; (i < nf); i++)
136 for (f = 0; (f < tfn[i].nfiles); f++)
138 sprintf(buf, "%4s %14s %-12s ", (f == 0) ? tfn[i].opt : "",
139 tfn[i].fns[f], (f == 0) ? fileopt(tfn[i].flag, opt_buf)
141 if (f < tfn[i].nfiles - 1)
143 fprintf(fp, "%s\n", buf);
146 if (tfn[i].nfiles > 0)
148 strcat(buf, ftp2desc(tfn[i].ftp));
149 if ((strlen(tfn[i].opt) > OPTLEN)
150 && (strlen(tfn[i].opt) <= ((OPTLEN + NAMELEN)
151 - strlen(tfn[i].fns[tfn[i].nfiles - 1]))))
153 for (j = strlen(tfn[i].opt); j < strlen(buf)
154 - (strlen(tfn[i].opt) - OPTLEN) + 1; j++)
156 buf[j] = buf[j + strlen(tfn[i].opt) - OPTLEN];
159 wbuf = wrap_lines(buf, 78, 35, FALSE);
160 fprintf(fp, "%s\n", wbuf);
170 /* name to print in help info for command line arguments
171 * (defined in enum in readinp.h) */
172 static const char *get_arg_desc(int type)
174 const char *const argtp[etNR] = {
175 "int", "step", "real", "time", "string", "bool", "vector", "enum"
180 /* Return the value of pa in the provided buffer buf, of size sz.
181 * The return value is also a pointer to buf.
183 static char *pa_val(t_pargs *pa, char buf[], int sz)
186 char buf_str[1256]; buf_str[0] = '\0';
190 GMX_RELEASE_ASSERT(sz >= 255, "Buffer must be at least 255 chars");
195 sprintf(buf, "%-d", *(pa->u.i));
198 sprintf(buf, "%" GMX_PRId64, *(pa->u.is));
203 sprintf(buf_str, "%-6g", r);
204 strcpy(buf, buf_str);
207 sprintf(buf, "%-6s", *(pa->u.b) ? "yes" : "no");
212 if (strlen(*(pa->u.c)) >= (size_t)sz)
214 gmx_fatal(FARGS, "Argument too long: \"%d\"\n", *(pa->u.c));
218 strcpy(buf, *(pa->u.c));
223 strcpy(buf, *(pa->u.c));
226 sprintf(buf, "%g %g %g", (*pa->u.rv)[0],
237 static char *pargs_print_line(t_pargs *pa, const gmx::HelpWriterContext &context)
239 char buf[LONGSTR], *buf2, *tmp;
241 snew(buf2, LONGSTR+strlen(pa->desc));
242 snew(tmp, LONGSTR+strlen(pa->desc));
244 if (pa->type == etBOOL)
246 sprintf(buf, "-[no]%s", pa->option+1);
250 strcpy(buf, pa->option);
252 std::string desc = check(pa->desc, context);
253 if ((int)strlen(buf) > ((OPTLEN+TYPELEN)-std::max((int)strlen(get_arg_desc(pa->type)), 4)))
255 sprintf(buf2, "%s %-6s %-6s %-s\n",
256 buf, get_arg_desc(pa->type), pa_val(pa, tmp, LONGSTR-1),
259 else if (strlen(buf) > OPTLEN)
261 /* so type can be 3 or 4 char's, this fits in the %4s */
262 sprintf(buf2, "%-14s %-4s %-6s %-s\n",
263 buf, get_arg_desc(pa->type), pa_val(pa, tmp, LONGSTR-1),
268 sprintf(buf2, "%-12s %-6s %-6s %-s\n",
269 buf, get_arg_desc(pa->type), pa_val(pa, tmp, LONGSTR-1),
274 tmp = wrap_lines(buf2, 78, 28, FALSE);
284 static void print_pargs(FILE *fp, int npargs, t_pargs pa[],
285 const gmx::HelpWriterContext &context)
289 fprintf(fp, "%-12s %-6s %-6s %-s\n",
290 "Option", "Type", "Value", "Description");
291 fprintf(fp, "------------------------------------------------------\n");
292 for (int i = 0; i < npargs; i++)
294 char *wdesc = pargs_print_line(&pa[i], context);
295 fprintf(fp, "%s", wdesc);
302 static void write_nroffman(FILE *out,
303 int nldesc, const char **desc,
304 int nfile, t_filenm *fnm,
305 int npargs, t_pargs *pa,
306 int nbug, const char **bugs,
307 const gmx::CommandLineHelpContext &context)
312 fprintf(out, ".SH SYNOPSIS\n");
313 fprintf(out, "\\f3%s\\fP\n", context.moduleDisplayName());
315 /* command line arguments */
318 for (i = 0; (i < nfile); i++)
320 fprintf(out, ".BI \"%s\" \" %s \"\n",
321 check(fnm[i].opt, context).c_str(),
322 check(fnm[i].fns[0], context).c_str());
327 for (i = 0; (i < npargs); i++)
329 if (pa[i].type == etBOOL)
331 fprintf(out, ".BI \"\\-[no]%s\" \"\"\n",
332 check(pa[i].option+1, context).c_str());
336 fprintf(out, ".BI \"%s\" \" %s \"\n",
337 check(pa[i].option, context).c_str(),
338 check(get_arg_desc(pa[i].type), context).c_str());
346 fprintf(out, ".SH DESCRIPTION\n");
347 for (i = 0; (i < nldesc); i++)
349 fprintf(out, "\\&%s\n", check(desc[i], context).c_str());
356 fprintf(out, ".SH FILES\n");
357 for (i = 0; (i < nfile); i++)
359 fprintf(out, ".BI \"%s\" \" %s\" \n.B %s\n %s \n\n",
360 check(fnm[i].opt, context).c_str(),
361 check(fnm[i].fns[0], context).c_str(),
362 check(fileopt(fnm[i].flag, tmp), context).c_str(),
363 check(ftp2desc(fnm[i].ftp), context).c_str());
368 fprintf(out, ".SH OTHER OPTIONS\n");
371 for (i = 0; (i < npargs); i++)
373 if (pa[i].type == etBOOL)
375 fprintf(out, ".BI \"\\-[no]%s\" \"%s\"\n %s\n\n",
376 check(pa[i].option+1, context).c_str(),
377 check(pa_val(&(pa[i]), tmp, 255), context).c_str(),
378 check(pa[i].desc, context).c_str());
382 fprintf(out, ".BI \"%s\" \" %s\" \" %s\" \n %s\n\n",
383 check(pa[i].option, context).c_str(),
384 check(get_arg_desc(pa[i].type), context).c_str(),
385 check(pa_val(&(pa[i]), tmp, 255), context).c_str(),
386 check(pa[i].desc, context).c_str());
393 fprintf(out, ".SH KNOWN PROBLEMS\n");
394 for (i = 0; (i < nbug); i++)
396 fprintf(out, "\\- %s\n\n", check(bugs[i], context).c_str());
402 print_tty_formatted(FILE *out, int nldesc, const char **desc,
403 const gmx::HelpWriterContext &context)
410 for (i = 0; (i < nldesc); i++)
412 if ((strlen(buf) > 0) &&
413 (buf[strlen(buf)-1] != ' ') && (buf[strlen(buf)-1] != '\n'))
417 std::string temp = check(desc[i], context);
418 if (strlen(buf) + temp.length() >= (size_t)(buflen-2))
420 buflen += temp.length();
423 strcat(buf, temp.c_str());
425 /* Make lines of at most 79 characters */
426 char *temp = wrap_lines(buf, 78, 0, FALSE);
427 fprintf(out, "%s\n", temp);
432 static void write_ttyman(FILE *out,
433 int nldesc, const char **desc,
434 int nfile, t_filenm *fnm,
435 int npargs, t_pargs *pa,
436 int nbug, const char **bugs,
437 const gmx::HelpWriterContext &context)
444 fprintf(out, "DESCRIPTION\n-----------\n");
445 print_tty_formatted(out, nldesc, desc, context);
450 fprintf(out, "KNOWN PROBLEMS\n----------\n");
451 for (i = 0; i < nbug; i++)
453 snew(tmp, strlen(bugs[i])+3);
455 strcpy(tmp+2, check(bugs[i], context).c_str());
456 fprintf(out, "%s\n", wrap_lines(tmp, 78, 2, FALSE));
463 pr_fns(out, nfile, fnm);
467 print_pargs(out, npargs, pa, context);
471 static void pr_html_files(FILE *out, int nfile, t_filenm fnm[],
472 const gmx::HelpWriterContext &context)
475 char link[10], tmp[255];
478 "<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=2>\n"
483 "<TH>description</TH>"
486 for (i = 0; (i < nfile); i++)
488 strcpy(link, ftp2ext(fnm[i].ftp));
489 if (strcmp(link, "???") == 0)
491 strcpy(link, "files");
495 "<TD ALIGN=RIGHT> <b><tt>%s</tt></b> </TD>"
496 "<TD ALIGN=RIGHT> <tt><a href=\"%s.html\">%12s</a></tt> </TD>"
500 fnm[i].opt, link, fnm[i].fns[0], fileopt(fnm[i].flag, tmp),
501 check(ftp2desc(fnm[i].ftp), context).c_str());
503 fprintf(out, "</TABLE>\n");
506 static void write_htmlman(FILE *out,
507 int nldesc, const char **desc,
508 int nfile, t_filenm *fnm,
509 int npargs, t_pargs *pa,
510 int nbug, const char **bugs,
511 const gmx::HelpWriterContext &context)
518 fprintf(out, "<H3>Description</H3>\n<p>\n");
519 for (i = 0; (i < nldesc); i++)
521 fprintf(out, "%s\n", check(desc[i], context).c_str());
526 fprintf(out, "<P>\n");
527 fprintf(out, "<H3>Files</H3>\n");
528 pr_html_files(out, nfile, fnm, context);
532 fprintf(out, "<P>\n");
533 fprintf(out, "<H3>Other options</H3>\n");
535 "<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=2>\n"
540 "<TH>description</TH>"
542 for (i = 0; (i < npargs); i++)
546 "<TD ALIGN=RIGHT> <b><tt>%s%s</tt></b> </TD>"
547 "<TD ALIGN=RIGHT> %s </TD>"
548 "<TD ALIGN=RIGHT> <tt>%s</tt> </TD>"
551 (pa[i].type == etBOOL) ? "-[no]" : "-", pa[i].option+1,
552 get_arg_desc(pa[i].type), pa_val(&(pa[i]), tmp, 255),
553 check(pa[i].desc, context).c_str());
555 fprintf(out, "</TABLE>\n");
559 fprintf(out, "<P>\n");
560 fprintf(out, "<H3>Known problems</H3>\n");
561 fprintf(out, "<UL>\n");
562 for (i = 0; (i < nbug); i++)
564 fprintf(out, "<LI>%s\n", check(bugs[i], context).c_str());
566 fprintf(out, "</UL>\n");
570 void write_man(const gmx::CommandLineHelpContext &context,
571 int nldesc, const char **desc,
572 int nfile, t_filenm *fnm,
573 int npargs, t_pargs *pa,
574 int nbug, const char **bugs)
576 FILE *out = context.writerContext().outputFile().handle();
577 const bool bHidden = context.showHidden();
591 for (int i = 0; i < npargs; i++)
593 if (!is_hidden(&pa[i]))
601 switch (context.writerContext().outputFormat())
603 case gmx::eHelpOutputFormat_Man:
604 write_nroffman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
607 case gmx::eHelpOutputFormat_Console:
608 write_ttyman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
609 context.writerContext());
611 case gmx::eHelpOutputFormat_Html:
612 write_htmlman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
613 context.writerContext());
616 GMX_THROW(gmx::NotImplementedError("Help format not implemented"));