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
37 #include "gromacs/commandline/cmdlinehelpcontext.h"
38 #include "gromacs/onlinehelp/wman.h"
39 #include "gromacs/utility/exceptions.h"
40 #include "gromacs/utility/file.h"
41 #include "gromacs/utility/stringutil.h"
43 #include "gmx_fatal.h"
47 #include "gromacs/fileio/filenm.h"
48 #include "gromacs/fileio/gmxfio.h"
55 /* The source code in this file should be thread-safe.
56 Please keep it that way. */
60 const char *search, *replace;
64 char *search, *replace;
67 /* The order of these arrays is significant. Text search and replace
68 * for each element occurs in order, so earlier changes can induce
69 * subsequent changes even though the original text might not appear
70 * to invoke the latter changes. */
72 const t_sandr_const sandrTty[] = {
85 { "[INT]", "integral" },
86 { "[FROM]", " from " },
95 { "[SQRT]", "sqrt(" },
109 { "[COSH]", "cosh(" },
111 { "[SINH]", "sinh(" },
113 { "[TANH]", "tanh(" },
120 #define NSRTTY asize(sandrTty)
122 const t_sandr_const sandrNROFF[] = {
131 { "[CHEVRON]", "<" },
132 { "[chevron]", ">" },
135 { "[INT]", "integral" },
136 { "[FROM]", " from " },
145 { "[SQRT]", "sqrt(" },
159 { "[COSH]", "cosh(" },
161 { "[SINH]", "sinh(" },
163 { "[TANH]", "tanh(" },
176 #define NSRNROFF asize(sandrNROFF)
178 const t_sandr_const sandrHTML[] = {
189 { "[CHEVRON]", "<" },
190 { "[chevron]", ">" },
193 { "[INT]", "integral" },
194 { "[FROM]", " from " },
203 { "[SQRT]", "sqrt(" },
217 { "[COSH]", "cosh(" },
219 { "[SINH]", "sinh(" },
221 { "[TANH]", "tanh(" },
228 #define NSRHTML asize(sandrHTML)
231 /* Data structure for saved HTML links */
232 typedef struct t_linkdata {
237 static t_linkdata *init_linkdata()
247 static void finish_linkdata(t_linkdata *p)
251 for (i = 0; i < p->nsr; i++)
253 sfree(p->sr[i].search);
254 sfree(p->sr[i].replace);
260 static char *repall(const char *s, int nsr, const t_sandr_const sa[])
264 std::string result(s);
265 for (int i = 0; i < nsr; ++i)
267 result = gmx::replaceAll(result, sa[i].search, sa[i].replace);
269 return gmx_strdup(result.c_str());
271 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
274 static char *repallww(const char *s, int nsr, const t_sandr sa[])
278 std::string result(s);
279 for (int i = 0; i < nsr; ++i)
281 result = gmx::replaceAllWords(result, sa[i].search, sa[i].replace);
283 return gmx_strdup(result.c_str());
285 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
288 static char *html_xref(char *s, const char *program, t_linkdata *links)
290 char buf[256], **filestr;
293 if (links->sr == NULL)
295 n = get_file("links.dat", &(filestr));
298 for (i = 0, j = 0; (i < n); i++)
300 if (!program || (gmx_strcasecmp(program, filestr[i]) != 0))
302 links->sr[j].search = gmx_strdup(filestr[i]);
303 sprintf(buf, "<a href=\"%s.html\">%s</a>", filestr[i], filestr[i]);
304 links->sr[j].replace = gmx_strdup(buf);
309 for (i = 0; i < n; i++)
315 return repallww(s, links->nsr, links->sr);
318 static char *check_nroff(const char *s)
320 return repall(s, NSRNROFF, sandrNROFF);
323 static char *check_html(const char *s, const char *program, t_linkdata *links)
327 buf = repall(s, NSRHTML, sandrHTML);
328 buf = html_xref(buf, program, links);
333 #define NSR(s) check_html(s, program, links)
335 #define FLAG_SET(flag, mask) ((flag &mask) == mask)
336 char *fileopt(unsigned long flag, char buf[], int maxsize)
340 if (FLAG_SET(flag, ffRW))
342 sprintf(tmp, "In/Out");
344 else if (FLAG_SET(flag, ffREAD))
346 sprintf(tmp, "Input");
348 else if (FLAG_SET(flag, ffWRITE))
350 sprintf(tmp, "Output");
354 sprintf(tmp, "Dunno");
357 if (FLAG_SET(flag, ffOPT))
359 strcat(tmp, ", Opt");
360 if (FLAG_SET(flag, ffSET))
369 if (FLAG_SET(flag, ffLIB))
371 strcat(tmp, ", Lib.");
373 if (FLAG_SET(flag, ffMULT))
375 strcat(tmp, ", Mult.");
378 sprintf(buf, "%s", tmp);
383 static void write_nroffman(FILE *out,
385 int nldesc, const char **desc,
386 int nfile, t_filenm *fnm,
387 int npargs, t_pargs *pa,
388 int nbug, const char **bugs,
395 fprintf(out, ".SH SYNOPSIS\n");
396 fprintf(out, "\\f3%s\\fP\n", program);
398 /* command line arguments */
401 for (i = 0; (i < nfile); i++)
403 fprintf(out, ".BI \"%s\" \" %s \"\n", check_nroff(fnm[i].opt),
404 check_nroff(fnm[i].fns[0]));
409 for (i = 0; (i < npargs); i++)
411 if (pa[i].type == etBOOL)
413 fprintf(out, ".BI \"\\-[no]%s\" \"\"\n", check_nroff(pa[i].option+1));
417 fprintf(out, ".BI \"%s\" \" %s \"\n", check_nroff(pa[i].option),
418 check_nroff(get_arg_desc(pa[i].type)));
426 fprintf(out, ".SH DESCRIPTION\n");
427 for (i = 0; (i < nldesc); i++)
429 fprintf(out, "\\&%s\n", check_nroff(desc[i]));
436 fprintf(out, ".SH FILES\n");
437 for (i = 0; (i < nfile); i++)
439 fprintf(out, ".BI \"%s\" \" %s\" \n.B %s\n %s \n\n",
440 check_nroff(fnm[i].opt),
441 check_nroff(fnm[i].fns[0]),
442 check_nroff(fileopt(fnm[i].flag, tmp, 255)),
443 check_nroff(ftp2desc(fnm[i].ftp)));
448 fprintf(out, ".SH OTHER OPTIONS\n");
451 for (i = 0; (i < npargs); i++)
453 if (pa[i].type == etBOOL)
455 fprintf(out, ".BI \"\\-[no]%s\" \"%s\"\n %s\n\n",
456 check_nroff(pa[i].option+1),
457 check_nroff(pa_val(&(pa[i]), tmp, 255)),
458 check_nroff(pa[i].desc));
462 fprintf(out, ".BI \"%s\" \" %s\" \" %s\" \n %s\n\n",
463 check_nroff(pa[i].option),
464 check_nroff(get_arg_desc(pa[i].type)),
465 check_nroff(pa_val(&(pa[i]), tmp, 255)),
466 check_nroff(pa[i].desc));
473 fprintf(out, ".SH KNOWN PROBLEMS\n");
474 for (i = 0; (i < nbug); i++)
476 fprintf(out, "\\- %s\n\n", check_nroff(bugs[i]));
481 char *check_tty(const char *s)
483 return repall(s, NSRTTY, sandrTty);
487 print_tty_formatted(FILE *out, int nldesc, const char **desc, int indent,
488 t_linkdata *links, const char *program)
496 for (i = 0; (i < nldesc); i++)
498 if ((strlen(buf) > 0) &&
499 (buf[strlen(buf)-1] != ' ') && (buf[strlen(buf)-1] != '\n'))
503 temp = check_tty(desc[i]);
504 if (strlen(buf) + strlen(temp) >= (size_t)(buflen-2))
506 buflen += strlen(temp);
512 /* Make lines of at most 79 characters */
513 temp = wrap_lines(buf, 78, indent, FALSE);
514 fprintf(out, "%s\n", temp);
519 static void write_ttyman(FILE *out,
521 int nldesc, const char **desc,
522 int nfile, t_filenm *fnm,
523 int npargs, t_pargs *pa,
524 int nbug, const char **bugs,
532 fprintf(out, "DESCRIPTION\n-----------\n");
533 print_tty_formatted(out, nldesc, desc, 0, links, program);
538 fprintf(out, "KNOWN PROBLEMS\n----------\n");
539 for (i = 0; i < nbug; i++)
541 snew(tmp, strlen(bugs[i])+3);
543 strcpy(tmp+2, check_tty(bugs[i]));
544 fprintf(out, "%s\n", wrap_lines(tmp, 78, 2, FALSE));
551 pr_fns(out, nfile, fnm);
555 print_pargs(out, npargs, pa);
559 static void pr_html_files(FILE *out, int nfile, t_filenm fnm[],
560 const char *program, t_linkdata *links)
563 char link[10], tmp[255];
566 "<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=2>\n"
571 "<TH>description</TH>"
574 for (i = 0; (i < nfile); i++)
576 strcpy(link, ftp2ext(fnm[i].ftp));
577 if (strcmp(link, "???") == 0)
579 strcpy(link, "files");
583 "<TD ALIGN=RIGHT> <b><tt>%s</tt></b> </TD>"
584 "<TD ALIGN=RIGHT> <tt><a href=\"%s.html\">%12s</a></tt> </TD>"
588 fnm[i].opt, link, fnm[i].fns[0], fileopt(fnm[i].flag, tmp, 255),
589 NSR(ftp2desc(fnm[i].ftp)));
592 fprintf(out, "</TABLE>\n");
595 static void write_htmlman(FILE *out,
597 int nldesc, const char **desc,
598 int nfile, t_filenm *fnm,
599 int npargs, t_pargs *pa,
600 int nbug, const char **bugs,
608 fprintf(out, "<H3>Description</H3>\n<p>\n");
609 for (i = 0; (i < nldesc); i++)
611 fprintf(out, "%s\n", NSR(desc[i]));
616 fprintf(out, "<P>\n");
617 fprintf(out, "<H3>Files</H3>\n");
618 pr_html_files(out, nfile, fnm, program, links);
622 fprintf(out, "<P>\n");
623 fprintf(out, "<H3>Other options</H3>\n");
625 "<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=2>\n"
630 "<TH>description</TH>"
632 for (i = 0; (i < npargs); i++)
636 "<TD ALIGN=RIGHT> <b><tt>%s%s</tt></b> </TD>"
637 "<TD ALIGN=RIGHT> %s </TD>"
638 "<TD ALIGN=RIGHT> <tt>%s</tt> </TD>"
641 (pa[i].type == etBOOL) ? "-[no]" : "-", pa[i].option+1,
642 get_arg_desc(pa[i].type), pa_val(&(pa[i]), tmp, 255), NSR(pa[i].desc));
644 fprintf(out, "</TABLE>\n");
648 fprintf(out, "<P>\n");
649 fprintf(out, "<H3>Known problems</H3>\n");
650 fprintf(out, "<UL>\n");
651 for (i = 0; (i < nbug); i++)
653 fprintf(out, "<LI>%s\n", NSR(bugs[i]));
655 fprintf(out, "</UL>\n");
659 static void pr_opts(FILE *fp,
660 int nfile, t_filenm *fnm,
661 int npargs, t_pargs pa[], int shell)
668 fprintf(fp, " \"c/-/(");
669 for (i = 0; i < nfile; i++)
671 fprintf(fp, " %s", fnm[i].opt+1);
673 for (i = 0; i < npargs; i++)
675 if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
677 fprintf(fp, " no%s", pa[i].option+1);
681 fprintf(fp, " %s", pa[i].option+1);
687 fprintf(fp, "if (( $COMP_CWORD <= 1 )) || [[ $c == -* ]]; then COMPREPLY=( $(compgen -W '");
688 for (i = 0; i < nfile; i++)
690 fprintf(fp, " -%s", fnm[i].opt+1);
692 for (i = 0; i < npargs; i++)
694 if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
696 fprintf(fp, " -no%s", pa[i].option+1);
700 fprintf(fp, " -%s", pa[i].option+1);
703 fprintf(fp, "' -- $c)); return 0; fi\n");
706 fprintf(fp, " -x 's[-]' -s \"");
707 for (i = 0; i < nfile; i++)
709 fprintf(fp, " %s", fnm[i].opt+1);
711 for (i = 0; i < npargs; i++)
713 if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
715 fprintf(fp, " no%s", pa[i].option+1);
719 fprintf(fp, " %s", pa[i].option+1);
727 static void write_cshcompl(FILE *out,
728 int nfile, t_filenm *fnm,
729 int npargs, t_pargs *pa)
731 fprintf(out, "complete %s", ShortProgram());
732 pr_enums(out, npargs, pa, eshellCSH);
733 pr_fopts(out, nfile, fnm, eshellCSH);
734 pr_opts(out, nfile, fnm, npargs, pa, eshellCSH);
738 static void write_zshcompl(FILE *out,
739 int nfile, t_filenm *fnm,
740 int npargs, t_pargs *pa)
742 fprintf(out, "compctl ");
744 /* start with options, since they are always present */
745 pr_opts(out, nfile, fnm, npargs, pa, eshellZSH);
746 pr_enums(out, npargs, pa, eshellZSH);
747 pr_fopts(out, nfile, fnm, eshellZSH);
748 fprintf(out, "-- %s\n", ShortProgram());
751 static void write_bashcompl(FILE *out,
752 int nfile, t_filenm *fnm,
753 int npargs, t_pargs *pa)
755 /* Advanced bash completions are handled by shell functions.
756 * p and c hold the previous and current word on the command line.
757 * We need to use extended globbing, so write it in each completion file */
758 fprintf(out, "shopt -s extglob\n");
759 fprintf(out, "_%s_compl() {\nlocal p c\n", ShortProgram());
760 fprintf(out, "COMPREPLY=() c=${COMP_WORDS[COMP_CWORD]} p=${COMP_WORDS[COMP_CWORD-1]}\n");
761 pr_opts(out, nfile, fnm, npargs, pa, eshellBASH);
762 fprintf(out, "case \"$p\" in\n");
764 pr_enums(out, npargs, pa, eshellBASH);
765 pr_fopts(out, nfile, fnm, eshellBASH);
766 fprintf(out, "esac }\ncomplete -F _%s_compl %s\n", ShortProgram(), ShortProgram());
769 void write_man(const char *mantp,
771 int nldesc, const char **desc,
772 int nfile, t_filenm *fnm,
773 int npargs, t_pargs *pa,
774 int nbug, const char **bugs)
776 bool bHidden = false;
782 links = init_linkdata();
784 const gmx::CommandLineHelpContext *context
785 = gmx::GlobalCommandLineHelpContext::get();
786 bool bFileOpened = false;
790 out = context->writerContext().outputFile().handle();
791 bHidden = context->showHidden();
796 sprintf(buf, "%s.%s", program, mantp);
797 out = gmx_fio_fopen(buf, "w");
810 for (int i = 0; i < npargs; i++)
812 if (!is_hidden(&pa[i]))
820 if (strcmp(mantp, "nroff") == 0)
822 write_nroffman(out, context->moduleDisplayName(), nldesc, desc,
823 nfile, fnm, npar, par, nbug, bugs, links);
825 if (strcmp(mantp, "help") == 0)
827 write_ttyman(out, program, nldesc, desc, nfile, fnm, npar, par, nbug, bugs, links);
829 if (strcmp(mantp, "html") == 0)
831 write_htmlman(out, program, nldesc, desc, nfile, fnm, npar, par, nbug, bugs, links);
833 if (strcmp(mantp, "completion-zsh") == 0)
835 write_zshcompl(out, nfile, fnm, npar, par);
837 if (strcmp(mantp, "completion-bash") == 0)
839 write_bashcompl(out, nfile, fnm, npar, par);
841 if (strcmp(mantp, "completion-csh") == 0)
843 write_cshcompl(out, nfile, fnm, npar, par);
856 finish_linkdata(links);
859 const char *get_arg_desc(int type)
861 static const char *argtp[etNR] = {
862 "int", "step", "real", "time", "string", "bool", "vector", "enum"