3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * GROningen Mixture of Alchemy and Childrens' Stories
40 #include "gromacs/commandline/cmdlinehelpcontext.h"
41 #include "gromacs/fileio/filenm.h"
42 #include "gromacs/fileio/gmxfio.h"
43 #include "gromacs/onlinehelp/wman.h"
44 #include "gromacs/utility/exceptions.h"
45 #include "gromacs/utility/file.h"
46 #include "gromacs/utility/gmxassert.h"
47 #include "gromacs/utility/stringutil.h"
55 /* The source code in this file should be thread-safe.
56 Please keep it that way. */
60 const char *search, *replace;
63 /* The order of these arrays is significant. Text search and replace
64 * for each element occurs in order, so earlier changes can induce
65 * subsequent changes even though the original text might not appear
66 * to invoke the latter changes. */
68 const t_sandr sandrTty[] = {
81 { "[INT]", "integral" },
82 { "[FROM]", " from " },
91 { "[SQRT]", "sqrt(" },
105 { "[COSH]", "cosh(" },
107 { "[SINH]", "sinh(" },
109 { "[TANH]", "tanh(" },
116 #define NSRTTY asize(sandrTty)
118 const t_sandr sandrNROFF[] = {
127 { "[CHEVRON]", "<" },
128 { "[chevron]", ">" },
131 { "[INT]", "integral" },
132 { "[FROM]", " from " },
141 { "[SQRT]", "sqrt(" },
155 { "[COSH]", "cosh(" },
157 { "[SINH]", "sinh(" },
159 { "[TANH]", "tanh(" },
172 #define NSRNROFF asize(sandrNROFF)
174 const t_sandr sandrHTML[] = {
185 { "[CHEVRON]", "<" },
186 { "[chevron]", ">" },
189 { "[INT]", "integral" },
190 { "[FROM]", " from " },
199 { "[SQRT]", "sqrt(" },
213 { "[COSH]", "cosh(" },
215 { "[SINH]", "sinh(" },
217 { "[TANH]", "tanh(" },
224 #define NSRHTML asize(sandrHTML)
226 static char *repall(const char *s, int nsr, const t_sandr sa[])
230 std::string result(s);
231 for (int i = 0; i < nsr; ++i)
233 result = gmx::replaceAll(result, sa[i].search, sa[i].replace);
235 return gmx_strdup(result.c_str());
237 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
240 char *check_nroff(const char *s)
242 return repall(s, NSRNROFF, sandrNROFF);
245 char *check_html(const char *s)
247 return repall(s, NSRHTML, sandrHTML);
250 std::string check(const char *s, const gmx::HelpWriterContext &context)
252 return context.substituteMarkupAndWrapToString(gmx::TextLineWrapperSettings(), s);
255 #define FLAG_SET(flag, mask) ((flag &mask) == mask)
256 char *fileopt(unsigned long flag, char buf[])
260 if (FLAG_SET(flag, ffRW))
262 sprintf(tmp, "In/Out");
264 else if (FLAG_SET(flag, ffREAD))
266 sprintf(tmp, "Input");
268 else if (FLAG_SET(flag, ffWRITE))
270 sprintf(tmp, "Output");
274 sprintf(tmp, "Dunno");
277 if (FLAG_SET(flag, ffOPT))
279 strcat(tmp, ", Opt");
280 if (FLAG_SET(flag, ffSET))
289 if (FLAG_SET(flag, ffLIB))
291 strcat(tmp, ", Lib.");
293 if (FLAG_SET(flag, ffMULT))
295 strcat(tmp, ", Mult.");
298 sprintf(buf, "%s", tmp);
303 static void write_nroffman(FILE *out,
305 int nldesc, const char **desc,
306 int nfile, t_filenm *fnm,
307 int npargs, t_pargs *pa,
308 int nbug, const char **bugs,
309 const gmx::HelpWriterContext &context)
314 fprintf(out, ".SH SYNOPSIS\n");
315 fprintf(out, "\\f3%s\\fP\n", program);
317 /* command line arguments */
320 for (i = 0; (i < nfile); i++)
322 fprintf(out, ".BI \"%s\" \" %s \"\n",
323 check(fnm[i].opt, context).c_str(),
324 check(fnm[i].fns[0], context).c_str());
329 for (i = 0; (i < npargs); i++)
331 if (pa[i].type == etBOOL)
333 fprintf(out, ".BI \"\\-[no]%s\" \"\"\n",
334 check(pa[i].option+1, context).c_str());
338 fprintf(out, ".BI \"%s\" \" %s \"\n",
339 check(pa[i].option, context).c_str(),
340 check(get_arg_desc(pa[i].type), context).c_str());
348 fprintf(out, ".SH DESCRIPTION\n");
349 for (i = 0; (i < nldesc); i++)
351 fprintf(out, "\\&%s\n", check(desc[i], context).c_str());
358 fprintf(out, ".SH FILES\n");
359 for (i = 0; (i < nfile); i++)
361 fprintf(out, ".BI \"%s\" \" %s\" \n.B %s\n %s \n\n",
362 check(fnm[i].opt, context).c_str(),
363 check(fnm[i].fns[0], context).c_str(),
364 check(fileopt(fnm[i].flag, tmp), context).c_str(),
365 check(ftp2desc(fnm[i].ftp), context).c_str());
370 fprintf(out, ".SH OTHER OPTIONS\n");
373 for (i = 0; (i < npargs); i++)
375 if (pa[i].type == etBOOL)
377 fprintf(out, ".BI \"\\-[no]%s\" \"%s\"\n %s\n\n",
378 check(pa[i].option+1, context).c_str(),
379 check(pa_val(&(pa[i]), tmp, 255), context).c_str(),
380 check(pa[i].desc, context).c_str());
384 fprintf(out, ".BI \"%s\" \" %s\" \" %s\" \n %s\n\n",
385 check(pa[i].option, context).c_str(),
386 check(get_arg_desc(pa[i].type), context).c_str(),
387 check(pa_val(&(pa[i]), tmp, 255), context).c_str(),
388 check(pa[i].desc, context).c_str());
395 fprintf(out, ".SH KNOWN PROBLEMS\n");
396 for (i = 0; (i < nbug); i++)
398 fprintf(out, "\\- %s\n\n", check(bugs[i], context).c_str());
403 char *check_tty(const char *s)
405 return repall(s, NSRTTY, sandrTty);
409 print_tty_formatted(FILE *out, int nldesc, const char **desc,
410 const gmx::HelpWriterContext &context)
417 for (i = 0; (i < nldesc); i++)
419 if ((strlen(buf) > 0) &&
420 (buf[strlen(buf)-1] != ' ') && (buf[strlen(buf)-1] != '\n'))
424 std::string temp = check(desc[i], context);
425 if (strlen(buf) + temp.length() >= (size_t)(buflen-2))
427 buflen += temp.length();
430 strcat(buf, temp.c_str());
432 /* Make lines of at most 79 characters */
433 char *temp = wrap_lines(buf, 78, 0, FALSE);
434 fprintf(out, "%s\n", temp);
439 static void write_ttyman(FILE *out,
440 int nldesc, const char **desc,
441 int nfile, t_filenm *fnm,
442 int npargs, t_pargs *pa,
443 int nbug, const char **bugs,
444 const gmx::HelpWriterContext &context)
451 fprintf(out, "DESCRIPTION\n-----------\n");
452 print_tty_formatted(out, nldesc, desc, context);
457 fprintf(out, "KNOWN PROBLEMS\n----------\n");
458 for (i = 0; i < nbug; i++)
460 snew(tmp, strlen(bugs[i])+3);
462 strcpy(tmp+2, check(bugs[i], context).c_str());
463 fprintf(out, "%s\n", wrap_lines(tmp, 78, 2, FALSE));
470 pr_fns(out, nfile, fnm);
474 print_pargs(out, npargs, pa);
478 static void pr_html_files(FILE *out, int nfile, t_filenm fnm[],
479 const gmx::HelpWriterContext &context)
482 char link[10], tmp[255];
485 "<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=2>\n"
490 "<TH>description</TH>"
493 for (i = 0; (i < nfile); i++)
495 strcpy(link, ftp2ext(fnm[i].ftp));
496 if (strcmp(link, "???") == 0)
498 strcpy(link, "files");
502 "<TD ALIGN=RIGHT> <b><tt>%s</tt></b> </TD>"
503 "<TD ALIGN=RIGHT> <tt><a href=\"%s.html\">%12s</a></tt> </TD>"
507 fnm[i].opt, link, fnm[i].fns[0], fileopt(fnm[i].flag, tmp),
508 check(ftp2desc(fnm[i].ftp), context).c_str());
510 fprintf(out, "</TABLE>\n");
513 static void write_htmlman(FILE *out,
514 int nldesc, const char **desc,
515 int nfile, t_filenm *fnm,
516 int npargs, t_pargs *pa,
517 int nbug, const char **bugs,
518 const gmx::HelpWriterContext &context)
525 fprintf(out, "<H3>Description</H3>\n<p>\n");
526 for (i = 0; (i < nldesc); i++)
528 fprintf(out, "%s\n", check(desc[i], context).c_str());
533 fprintf(out, "<P>\n");
534 fprintf(out, "<H3>Files</H3>\n");
535 pr_html_files(out, nfile, fnm, context);
539 fprintf(out, "<P>\n");
540 fprintf(out, "<H3>Other options</H3>\n");
542 "<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=2>\n"
547 "<TH>description</TH>"
549 for (i = 0; (i < npargs); i++)
553 "<TD ALIGN=RIGHT> <b><tt>%s%s</tt></b> </TD>"
554 "<TD ALIGN=RIGHT> %s </TD>"
555 "<TD ALIGN=RIGHT> <tt>%s</tt> </TD>"
558 (pa[i].type == etBOOL) ? "-[no]" : "-", pa[i].option+1,
559 get_arg_desc(pa[i].type), pa_val(&(pa[i]), tmp, 255),
560 check(pa[i].desc, context).c_str());
562 fprintf(out, "</TABLE>\n");
566 fprintf(out, "<P>\n");
567 fprintf(out, "<H3>Known problems</H3>\n");
568 fprintf(out, "<UL>\n");
569 for (i = 0; (i < nbug); i++)
571 fprintf(out, "<LI>%s\n", check(bugs[i], context).c_str());
573 fprintf(out, "</UL>\n");
577 static void pr_opts(FILE *fp,
578 int nfile, t_filenm *fnm,
579 int npargs, t_pargs pa[], int shell)
586 fprintf(fp, " \"c/-/(");
587 for (i = 0; i < nfile; i++)
589 fprintf(fp, " %s", fnm[i].opt+1);
591 for (i = 0; i < npargs; i++)
593 if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
595 fprintf(fp, " no%s", pa[i].option+1);
599 fprintf(fp, " %s", pa[i].option+1);
605 fprintf(fp, "if (( $COMP_CWORD <= 1 )) || [[ $c == -* ]]; then COMPREPLY=( $(compgen -W '");
606 for (i = 0; i < nfile; i++)
608 fprintf(fp, " -%s", fnm[i].opt+1);
610 for (i = 0; i < npargs; i++)
612 if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
614 fprintf(fp, " -no%s", pa[i].option+1);
618 fprintf(fp, " -%s", pa[i].option+1);
621 fprintf(fp, "' -- $c)); return 0; fi\n");
624 fprintf(fp, " -x 's[-]' -s \"");
625 for (i = 0; i < nfile; i++)
627 fprintf(fp, " %s", fnm[i].opt+1);
629 for (i = 0; i < npargs; i++)
631 if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
633 fprintf(fp, " no%s", pa[i].option+1);
637 fprintf(fp, " %s", pa[i].option+1);
645 static void write_cshcompl(FILE *out,
646 int nfile, t_filenm *fnm,
647 int npargs, t_pargs *pa)
649 fprintf(out, "complete %s", ShortProgram());
650 pr_enums(out, npargs, pa, eshellCSH);
651 pr_fopts(out, nfile, fnm, eshellCSH);
652 pr_opts(out, nfile, fnm, npargs, pa, eshellCSH);
656 static void write_zshcompl(FILE *out,
657 int nfile, t_filenm *fnm,
658 int npargs, t_pargs *pa)
660 fprintf(out, "compctl ");
662 /* start with options, since they are always present */
663 pr_opts(out, nfile, fnm, npargs, pa, eshellZSH);
664 pr_enums(out, npargs, pa, eshellZSH);
665 pr_fopts(out, nfile, fnm, eshellZSH);
666 fprintf(out, "-- %s\n", ShortProgram());
669 static void write_bashcompl(FILE *out,
670 int nfile, t_filenm *fnm,
671 int npargs, t_pargs *pa)
673 /* Advanced bash completions are handled by shell functions.
674 * p and c hold the previous and current word on the command line.
675 * We need to use extended globbing, so write it in each completion file */
676 fprintf(out, "shopt -s extglob\n");
677 fprintf(out, "_%s_compl() {\nlocal p c\n", ShortProgram());
678 fprintf(out, "COMPREPLY=() c=${COMP_WORDS[COMP_CWORD]} p=${COMP_WORDS[COMP_CWORD-1]}\n");
679 pr_opts(out, nfile, fnm, npargs, pa, eshellBASH);
680 fprintf(out, "case \"$p\" in\n");
682 pr_enums(out, npargs, pa, eshellBASH);
683 pr_fopts(out, nfile, fnm, eshellBASH);
684 fprintf(out, "esac }\ncomplete -F _%s_compl %s\n", ShortProgram(), ShortProgram());
687 void write_man(const char *mantp,
689 int nldesc, const char **desc,
690 int nfile, t_filenm *fnm,
691 int npargs, t_pargs *pa,
692 int nbug, const char **bugs)
694 bool bHidden = false;
698 const gmx::CommandLineHelpContext *context
699 = gmx::GlobalCommandLineHelpContext::get();
700 bool bFileOpened = false;
704 out = context->writerContext().outputFile().handle();
705 bHidden = context->showHidden();
710 sprintf(buf, "%s.%s", program, mantp);
711 out = gmx_fio_fopen(buf, "w");
724 for (int i = 0; i < npargs; i++)
726 if (!is_hidden(&pa[i]))
734 if (strcmp(mantp, "nroff") == 0)
736 GMX_RELEASE_ASSERT(context != NULL,
737 "Man page export only implemented with the new context");
738 write_nroffman(out, context->moduleDisplayName(), nldesc, desc,
739 nfile, fnm, npar, par, nbug, bugs,
740 context->writerContext());
742 if (strcmp(mantp, "help") == 0)
744 GMX_RELEASE_ASSERT(context != NULL,
745 "Help export only implemented with the new context");
746 write_ttyman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
747 context->writerContext());
749 if (strcmp(mantp, "html") == 0)
751 GMX_RELEASE_ASSERT(context != NULL,
752 "HTML export only implemented with the new context");
753 write_htmlman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
754 context->writerContext());
756 if (strcmp(mantp, "completion-zsh") == 0)
758 write_zshcompl(out, nfile, fnm, npar, par);
760 if (strcmp(mantp, "completion-bash") == 0)
762 write_bashcompl(out, nfile, fnm, npar, par);
764 if (strcmp(mantp, "completion-csh") == 0)
766 write_cshcompl(out, nfile, fnm, npar, par);
780 const char *get_arg_desc(int type)
782 static const char *argtp[etNR] = {
783 "int", "step", "real", "time", "string", "bool", "vector", "enum"