Man page export from the wrapper binary.
[alexxy/gromacs.git] / src / gromacs / onlinehelp / wman.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  *                        VERSION 3.2.0
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.
14
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.
19  *
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.
26  *
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.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * GROningen Mixture of Alchemy and Childrens' Stories
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <time.h>
40
41 #include <string>
42
43 #include "gromacs/commandline/cmdlinehelpcontext.h"
44 #include "gromacs/onlinehelp/wman.h"
45 #include "gromacs/utility/exceptions.h"
46 #include "gromacs/utility/file.h"
47 #include "gromacs/utility/stringutil.h"
48
49 #include "gmx_fatal.h"
50 #include "string2.h"
51 #include "smalloc.h"
52 #include "sysstuff.h"
53 #include "filenm.h"
54 #include "macros.h"
55 #include "statutil.h"
56 #include "copyrite.h"
57 #include "strdb.h"
58 #include "readinp.h"
59
60 /* The source code in this file should be thread-safe.
61          Please keep it that way. */
62
63
64 typedef struct {
65     const char *search, *replace;
66 } t_sandr_const;
67
68 typedef struct {
69     char *search, *replace;
70 } t_sandr;
71
72 /* The order of these arrays is significant. Text search and replace
73  * for each element occurs in order, so earlier changes can induce
74  * subsequent changes even though the original text might not appear
75  * to invoke the latter changes. */
76
77 const t_sandr_const sandrTeX[] = {
78     { "[TT]", "{\\tt " },
79     { "[tt]", "}"      },
80     { "[BB]", "{\\bf " },
81     { "[bb]", "}"      },
82     { "[IT]", "{\\em " },
83     { "[it]", "}"      },
84     { "[PAR]", "\n\n"   },
85     /* Escaping underscore for LaTeX is no longer necessary, and it breaks
86      * text searching and the index if you do. */
87     /*
88        { "_",    "\\_"    },
89      */
90     { "$",    "\\$"    },
91     { "<=",   "\\ensuremath{\\leq{}}"},
92     { ">=",   "\\ensuremath{\\geq{}}"},
93     { "<",    "\\textless{}" },
94     { ">",    "\\textgreater{}" },
95     { "^",    "\\^{}"    },
96     { "\\^{}t", "\\ensuremath{^t}" },
97     { "\\^{}a", "\\ensuremath{^a}" },
98     { "\\^{}b", "\\ensuremath{^b}" },
99     { "\\^{}2", "\\ensuremath{^2}" },
100     { "\\^{}3", "\\ensuremath{^3}" },
101     { "\\^{}6", "\\ensuremath{^6}" },
102     { "#",    "\\#"    },
103     { "[BR]", "\\\\"   },
104     { "%",    "\\%"    },
105     { "&",    "\\&"    },
106     /* The next couple of lines allow true Greek symbols to be written to the
107        manual, which makes it look pretty */
108     { "[GRK]", "\\ensuremath{\\" },
109     { "[grk]", "}" },
110     { "[MATH]", "\\ensuremath{" },
111     { "[math]", "}" },
112     { "[CHEVRON]", "\\ensuremath{<}" },
113     { "[chevron]", "\\ensuremath{>}" },
114     { "[MAG]", "\\ensuremath{|}" },
115     { "[mag]", "\\ensuremath{|}" },
116     { "[INT]", "\\ensuremath{\\int" },
117     { "[FROM]", "_" },
118     { "[from]", "" },
119     { "[TO]", "^" },
120     { "[to]", "" },
121     { "[int]", "}" },
122     { "[SUM]", "\\ensuremath{\\sum" },
123     { "[sum]", "}" },
124     { "[SUB]", "\\ensuremath{_{" },
125     { "[sub]", "}}" },
126     { "[SQRT]", "\\ensuremath{\\sqrt{" },
127     { "[sqrt]", "}}" },
128     { "[EXP]", "\\ensuremath{\\exp{(" },
129     { "[exp]", ")}}" },
130     { "[LN]", "\\ensuremath{\\ln{(" },
131     { "[ln]", ")}}" },
132     { "[LOG]", "\\ensuremath{\\log{(" },
133     { "[log]", ")}}" },
134     { "[COS]", "\\ensuremath{\\cos{(" },
135     { "[cos]", ")}}" },
136     { "[SIN]", "\\ensuremath{\\sin{(" },
137     { "[sin]", ")}}" },
138     { "[TAN]", "\\ensuremath{\\tan{(" },
139     { "[tan]", ")}}" },
140     { "[COSH]", "\\ensuremath{\\cosh{(" },
141     { "[cosh]", ")}}" },
142     { "[SINH]", "\\ensuremath{\\sinh{(" },
143     { "[sinh]", ")}}" },
144     { "[TANH]", "\\ensuremath{\\tanh{(" },
145     { "[tanh]", ")}}" }
146 };
147 #define NSRTEX asize(sandrTeX)
148
149 const t_sandr_const sandrTty[] = {
150     { "[TT]", "" },
151     { "[tt]", "" },
152     { "[BB]", "" },
153     { "[bb]", "" },
154     { "[IT]", "" },
155     { "[it]", "" },
156     { "[MATH]", "" },
157     { "[math]", "" },
158     { "[CHEVRON]", "<" },
159     { "[chevron]", ">" },
160     { "[MAG]", "|" },
161     { "[mag]", "|" },
162     { "[INT]", "integral" },
163     { "[FROM]", " from " },
164     { "[from]", "" },
165     { "[TO]", " to " },
166     { "[to]", " of" },
167     { "[int]", "" },
168     { "[SUM]", "sum" },
169     { "[sum]", "" },
170     { "[SUB]", "_" },
171     { "[sub]", "" },
172     { "[SQRT]", "sqrt(" },
173     { "[sqrt]", ")" },
174     { "[EXP]", "exp(" },
175     { "[exp]", ")" },
176     { "[LN]", "ln(" },
177     { "[ln]", ")" },
178     { "[LOG]", "log(" },
179     { "[log]", ")" },
180     { "[COS]", "cos(" },
181     { "[cos]", ")" },
182     { "[SIN]", "sin(" },
183     { "[sin]", ")" },
184     { "[TAN]", "tan(" },
185     { "[tan]", ")" },
186     { "[COSH]", "cosh(" },
187     { "[cosh]", ")" },
188     { "[SINH]", "sinh(" },
189     { "[sinh]", ")" },
190     { "[TANH]", "tanh(" },
191     { "[tanh]", ")" },
192     { "[PAR]", "\n\n" },
193     { "[BR]", "\n"},
194     { "[GRK]", "" },
195     { "[grk]", "" }
196 };
197 #define NSRTTY asize(sandrTty)
198
199 const t_sandr_const sandrNROFF[] = {
200     { "[TT]", "\\fB " },
201     { "[tt]", "\\fR" },
202     { "[BB]", "\\fB " },
203     { "[bb]", "\\fR" },
204     { "[IT]", "\\fI " },
205     { "[it]", "\\fR" },
206     { "[MATH]", "" },
207     { "[math]", "" },
208     { "[CHEVRON]", "<" },
209     { "[chevron]", ">" },
210     { "[MAG]", "|" },
211     { "[mag]", "|" },
212     { "[INT]", "integral" },
213     { "[FROM]", " from " },
214     { "[from]", "" },
215     { "[TO]", " to " },
216     { "[to]", " of" },
217     { "[int]", "" },
218     { "[SUM]", "sum" },
219     { "[sum]", "" },
220     { "[SUB]", "_" },
221     { "[sub]", "" },
222     { "[SQRT]", "sqrt(" },
223     { "[sqrt]", ")", },
224     { "[EXP]", "exp(" },
225     { "[exp]", ")" },
226     { "[LN]", "ln(" },
227     { "[ln]", ")" },
228     { "[LOG]", "log(" },
229     { "[log]", ")" },
230     { "[COS]", "cos(" },
231     { "[cos]", ")" },
232     { "[SIN]", "sin(" },
233     { "[sin]", ")" },
234     { "[TAN]", "tan(" },
235     { "[tan]", ")" },
236     { "[COSH]", "cosh(" },
237     { "[cosh]", ")" },
238     { "[SINH]", "sinh(" },
239     { "[sinh]", ")" },
240     { "[TANH]", "tanh(" },
241     { "[tanh]", ")" },
242     { "[PAR]", "\n\n" },
243     { "\n ",    "\n" },
244     { "<",    "" },
245     { ">",    "" },
246     { "^",    "" },
247     { "#",    "" },
248     { "[BR]", "\n"},
249     { "-",    "\\-"},
250     { "[GRK]", "" },
251     { "[grk]", "" }
252 };
253 #define NSRNROFF asize(sandrNROFF)
254
255 const t_sandr_const sandrHTML[] = {
256     { "<",    "&lt;" },
257     { ">",    "&gt;" },
258     { "[TT]", "<tt>" },
259     { "[tt]", "</tt>" },
260     { "[BB]", "<b>" },
261     { "[bb]", "</b>" },
262     { "[IT]", "<it>" },
263     { "[it]", "</it>" },
264     { "[MATH]", "" },
265     { "[math]", "" },
266     { "[CHEVRON]", "<" },
267     { "[chevron]", ">" },
268     { "[MAG]", "|" },
269     { "[mag]", "|" },
270     { "[INT]", "integral" },
271     { "[FROM]", " from " },
272     { "[from]", "" },
273     { "[TO]", " to " },
274     { "[to]", " of" },
275     { "[int]", "" },
276     { "[SUM]", "sum" },
277     { "[sum]", "" },
278     { "[SUB]", "_" },
279     { "[sub]", "" },
280     { "[SQRT]", "sqrt(" },
281     { "[sqrt]", ")", },
282     { "[EXP]", "exp(" },
283     { "[exp]", ")" },
284     { "[LN]", "ln(" },
285     { "[ln]", ")" },
286     { "[LOG]", "log(" },
287     { "[log]", ")" },
288     { "[COS]", "cos(" },
289     { "[cos]", ")" },
290     { "[SIN]", "sin(" },
291     { "[sin]", ")" },
292     { "[TAN]", "tan(" },
293     { "[tan]", ")" },
294     { "[COSH]", "cosh(" },
295     { "[cosh]", ")" },
296     { "[SINH]", "sinh(" },
297     { "[sinh]", ")" },
298     { "[TANH]", "tanh(" },
299     { "[tanh]", ")" },
300     { "[PAR]", "<p>" },
301     { "[BR]", "<br>" },
302     { "[GRK]", "&"  },
303     { "[grk]", ";"  }
304 };
305 #define NSRHTML asize(sandrHTML)
306
307
308 static char *mydate(char buf[], int maxsize)
309 {
310     const char *mon[] = {
311         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
312         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
313     };
314     const char *day[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
315     time_t      now;
316     struct tm   tm;
317
318     time(&now);
319 #ifdef GMX_NATIVE_WINDOWS
320     /* Native windows */
321     localtime_s(&tm, &now);
322 #else
323     localtime_r(&now, &tm);
324 #endif
325
326     sprintf(buf, "%s %d %s %d", day[tm.tm_wday], tm.tm_mday,
327             mon[tm.tm_mon], tm.tm_year+1900);
328
329     return buf;
330 }
331
332 /* Data structure for saved HTML links */
333 typedef struct t_linkdata {
334     int      nsr;
335     t_sandr *sr;
336 } t_linkdata;
337
338 static t_linkdata *init_linkdata()
339 {
340     t_linkdata *p;
341     snew(p, 1);
342     p->sr  = NULL;
343     p->nsr = 0;
344
345     return p;
346 }
347
348 static void finish_linkdata(t_linkdata *p)
349 {
350     int i;
351
352     for (i = 0; i < p->nsr; i++)
353     {
354         sfree(p->sr[i].search);
355         sfree(p->sr[i].replace);
356     }
357     sfree(p->sr);
358     sfree(p);
359 }
360
361 static char *repall(const char *s, int nsr, const t_sandr_const sa[])
362 {
363     try
364     {
365         std::string result(s);
366         for (int i = 0; i < nsr; ++i)
367         {
368             result = gmx::replaceAll(result, sa[i].search, sa[i].replace);
369         }
370         return gmx_strdup(result.c_str());
371     }
372     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
373 }
374
375 static char *repallww(const char *s, int nsr, const t_sandr sa[])
376 {
377     try
378     {
379         std::string result(s);
380         for (int i = 0; i < nsr; ++i)
381         {
382             result = gmx::replaceAllWords(result, sa[i].search, sa[i].replace);
383         }
384         return gmx_strdup(result.c_str());
385     }
386     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
387 }
388
389 static char *html_xref(char *s, const char *program, t_linkdata *links)
390 {
391     char   buf[256], **filestr;
392     int    i, j, n;
393
394     if (links->sr == NULL)
395     {
396         n          = get_file("links.dat", &(filestr));
397         links->nsr = n;
398         snew(links->sr, n);
399         for (i = 0, j = 0; (i < n); i++)
400         {
401             if (!program || (gmx_strcasecmp(program, filestr[i])  != 0))
402             {
403                 links->sr[j].search = gmx_strdup(filestr[i]);
404                 sprintf(buf, "<a href=\"%s.html\">%s</a>", filestr[i], filestr[i]);
405                 links->sr[j].replace = gmx_strdup(buf);
406                 j++;
407             }
408         }
409         links->nsr = j;
410         for (i = 0; i < n; i++)
411         {
412             sfree(filestr[i]);
413         }
414         sfree(filestr);
415     }
416     return repallww(s, links->nsr, links->sr);
417 }
418
419 char *check_tex(const char *s)
420 {
421     return repall(s, NSRTEX, sandrTeX);
422 }
423
424 static char *check_nroff(const char *s)
425 {
426     return repall(s, NSRNROFF, sandrNROFF);
427 }
428
429 static char *check_html(const char *s, const char *program, t_linkdata *links)
430 {
431     char *buf;
432
433     buf = repall(s, NSRHTML, sandrHTML);
434     buf = html_xref(buf, program, links);
435
436     return buf;
437 }
438
439 #define NSR(s) check_html(s, program, links)
440
441 #define FLAG_SET(flag, mask) ((flag &mask) == mask)
442 char *fileopt(unsigned long flag, char buf[], int maxsize)
443 {
444     char tmp[256];
445
446     if (FLAG_SET(flag, ffRW))
447     {
448         sprintf(tmp, "In/Out");
449     }
450     else if (FLAG_SET(flag, ffREAD))
451     {
452         sprintf(tmp, "Input");
453     }
454     else if (FLAG_SET(flag, ffWRITE))
455     {
456         sprintf(tmp, "Output");
457     }
458     else
459     {
460         sprintf(tmp, "Dunno");
461     }
462
463     if (FLAG_SET(flag, ffOPT))
464     {
465         strcat(tmp, ", Opt");
466         if (FLAG_SET(flag, ffSET))
467         {
468             strcat(tmp, "!");
469         }
470         else
471         {
472             strcat(tmp, ".");
473         }
474     }
475     if (FLAG_SET(flag, ffLIB))
476     {
477         strcat(tmp, ", Lib.");
478     }
479     if (FLAG_SET(flag, ffMULT))
480     {
481         strcat(tmp, ", Mult.");
482     }
483
484     sprintf(buf, "%s", tmp);
485
486     return buf;
487 }
488
489 static void write_texman(FILE *out, const char *program,
490                          int nldesc, const char **desc,
491                          int nfile, t_filenm *fnm,
492                          int npargs, t_pargs *pa,
493                          int nbug, const char **bugs,
494                          t_linkdata *links)
495 {
496     int  i;
497     char tmp[256];
498
499     fprintf(out, "\\section{\\normindex{%s}}\\label{%s}\n\n", check_tex(program), check_tex(program));
500
501     if (nldesc > 0)
502     {
503         for (i = 0; (i < nldesc); i++)
504         {
505             fprintf(out, "%s\n", check_tex(desc[i]));
506         }
507     }
508
509     if (nfile > 0)
510     {
511         fprintf(out, "\\vspace{-2ex}\\begin{tabbing}\n");
512         fprintf(out, "\n{\\normalsize \\bf Files}\\nopagebreak\\\\\n");
513         fprintf(out, "{\\tt ~~~~~~~} \\= {\\tt ~~~~~~~~~~~~~~} \\= "
514                 "~~~~~~~~~~~~~~~~~~~~~~ \\= \\nopagebreak\\kill\n");
515         for (i = 0; (i < nfile); i++)
516         {
517             fprintf(out, "\\>{\\tt %s} \\'\\> {\\tt %s} \\' %s \\> "
518                     "\\parbox[t]{0.55\\linewidth}{%s} \\\\\n",
519                     check_tex(fnm[i].opt), check_tex(fnm[i].fns[0]),
520                     check_tex(fileopt(fnm[i].flag, tmp, 255)),
521                     check_tex(ftp2desc(fnm[i].ftp)));
522         }
523         fprintf(out, "\\end{tabbing}\\vspace{-4ex}\n");
524     }
525     if (npargs > 0)
526     {
527         fprintf(out, "\\vspace{-2ex}\\begin{tabbing}\n");
528         fprintf(out, "\n{\\normalsize \\bf Other options}\\nopagebreak\\\\\n");
529         fprintf(out, "{\\tt ~~~~~~~~~~} \\= vector \\= "
530                 "{\\tt ~~~~~~~} \\= \\nopagebreak\\kill\n");
531         for (i = 0; (i < npargs); i++)
532         {
533             if (strlen(check_tex(pa_val(&(pa[i]), tmp, 255))) <= 8)
534             {
535                 fprintf(out, "\\> {\\tt %s} \\'\\> %s \\'\\> {\\tt %s} \\' "
536                         "\\parbox[t]{0.68\\linewidth}{%s}\\\\\n",
537                         check_tex(pa[i].option), get_arg_desc(pa[i].type),
538                         check_tex(pa_val(&(pa[i]), tmp, 255)),
539                         check_tex(pa[i].desc));
540             }
541             else
542             {
543                 fprintf(out, "\\> {\\tt %s} \\'\\> %s \\'\\>\\\\\n"
544                         "\\> \\'\\> \\'\\> {\\tt %s} \\' "
545                         "\\parbox[t]{0.7\\linewidth}{%s}\\\\\n",
546                         check_tex(pa[i].option), get_arg_desc(pa[i].type),
547                         check_tex(pa_val(&(pa[i]), tmp, 255)),
548                         check_tex(pa[i].desc));
549             }
550         }
551         fprintf(out, "\\end{tabbing}\\vspace{-4ex}\n");
552     }
553     if (nbug > 0)
554     {
555         fprintf(out, "\n");
556         fprintf(out, "\\begin{itemize}\n");
557         for (i = 0; (i < nbug); i++)
558         {
559             fprintf(out, "\\item %s\n", check_tex(bugs[i]));
560         }
561         fprintf(out, "\\end{itemize}\n");
562     }
563 /*   fprintf(out,"\n\\newpage\n"); */
564 }
565
566 static void write_nroffman(FILE *out,
567                            const char *program,
568                            int nldesc, const char **desc,
569                            int nfile, t_filenm *fnm,
570                            int npargs, t_pargs *pa,
571                            int nbug, const char **bugs,
572                            t_linkdata *links)
573
574 {
575     int  i;
576     char tmp[256];
577
578     fprintf(out, ".SH SYNOPSIS\n");
579     fprintf(out, "\\f3%s\\fP\n", program);
580
581     /* command line arguments */
582     if (nfile > 0)
583     {
584         for (i = 0; (i < nfile); i++)
585         {
586             fprintf(out, ".BI \"%s\" \" %s \"\n", check_nroff(fnm[i].opt),
587                     check_nroff(fnm[i].fns[0]));
588         }
589     }
590     if (npargs > 0)
591     {
592         for (i = 0; (i < npargs); i++)
593         {
594             if (pa[i].type == etBOOL)
595             {
596                 fprintf(out, ".BI \"\\-[no]%s\" \"\"\n", check_nroff(pa[i].option+1));
597             }
598             else
599             {
600                 fprintf(out, ".BI \"%s\" \" %s \"\n", check_nroff(pa[i].option),
601                         check_nroff(get_arg_desc(pa[i].type)));
602             }
603         }
604     }
605
606     /* description */
607     if (nldesc > 0)
608     {
609         fprintf(out, ".SH DESCRIPTION\n");
610         for (i = 0; (i < nldesc); i++)
611         {
612             fprintf(out, "\\&%s\n", check_nroff(desc[i]));
613         }
614     }
615
616     /* FILES */
617     if (nfile > 0)
618     {
619         fprintf(out, ".SH FILES\n");
620         for (i = 0; (i < nfile); i++)
621         {
622             fprintf(out, ".BI \"%s\" \" %s\" \n.B %s\n %s \n\n",
623                     check_nroff(fnm[i].opt),
624                     check_nroff(fnm[i].fns[0]),
625                     check_nroff(fileopt(fnm[i].flag, tmp, 255)),
626                     check_nroff(ftp2desc(fnm[i].ftp)));
627         }
628     }
629
630     /* other options */
631     fprintf(out, ".SH OTHER OPTIONS\n");
632     if (npargs > 0)
633     {
634         for (i = 0; (i < npargs); i++)
635         {
636             if (pa[i].type == etBOOL)
637             {
638                 fprintf(out, ".BI \"\\-[no]%s\"  \"%s\"\n %s\n\n",
639                         check_nroff(pa[i].option+1),
640                         check_nroff(pa_val(&(pa[i]), tmp, 255)),
641                         check_nroff(pa[i].desc));
642             }
643             else
644             {
645                 fprintf(out, ".BI \"%s\"  \" %s\" \" %s\" \n %s\n\n",
646                         check_nroff(pa[i].option),
647                         check_nroff(get_arg_desc(pa[i].type)),
648                         check_nroff(pa_val(&(pa[i]), tmp, 255)),
649                         check_nroff(pa[i].desc));
650             }
651         }
652     }
653
654     if (nbug > 0)
655     {
656         fprintf(out, ".SH KNOWN PROBLEMS\n");
657         for (i = 0; (i < nbug); i++)
658         {
659             fprintf(out, "\\- %s\n\n", check_nroff(bugs[i]));
660         }
661     }
662 }
663
664 char *check_tty(const char *s)
665 {
666     return repall(s, NSRTTY, sandrTty);
667 }
668
669 static void
670 print_tty_formatted(FILE *out, int nldesc, const char **desc, int indent,
671                     t_linkdata *links, const char *program)
672 {
673     char *buf;
674     char *temp;
675     int   buflen, i;
676
677     buflen = 80*nldesc;
678     snew(buf, buflen);
679     for (i = 0; (i < nldesc); i++)
680     {
681         if ((strlen(buf) > 0) &&
682             (buf[strlen(buf)-1] != ' ') && (buf[strlen(buf)-1] != '\n'))
683         {
684             strcat(buf, " ");
685         }
686         temp = check_tty(desc[i]);
687         if (strlen(buf) + strlen(temp) >= (size_t)(buflen-2))
688         {
689             buflen += strlen(temp);
690             srenew(buf, buflen);
691         }
692         strcat(buf, temp);
693         sfree(temp);
694     }
695     /* Make lines of at most 79 characters */
696     temp = wrap_lines(buf, 78, indent, FALSE);
697     fprintf(out, "%s\n", temp);
698     sfree(temp);
699     sfree(buf);
700 }
701
702 static void write_ttyman(FILE *out,
703                          const char *program,
704                          int nldesc, const char **desc,
705                          int nfile, t_filenm *fnm,
706                          int npargs, t_pargs *pa,
707                          int nbug, const char **bugs,
708                          t_linkdata *links)
709 {
710     int   i;
711     char *tmp;
712
713     if (nldesc > 0)
714     {
715         fprintf(out, "DESCRIPTION\n-----------\n");
716         print_tty_formatted(out, nldesc, desc, 0, links, program);
717     }
718     if (nbug > 0)
719     {
720         fprintf(out, "\n");
721         fprintf(out, "KNOWN PROBLEMS\n----------\n");
722         for (i = 0; i < nbug; i++)
723         {
724             snew(tmp, strlen(bugs[i])+3);
725             strcpy(tmp, "* ");
726             strcpy(tmp+2, check_tty(bugs[i]));
727             fprintf(out, "%s\n", wrap_lines(tmp, 78, 2, FALSE));
728             sfree(tmp);
729         }
730     }
731     if (nfile > 0)
732     {
733         fprintf(out, "\n");
734         pr_fns(out, nfile, fnm);
735     }
736     if (npargs > 0)
737     {
738         print_pargs(out, npargs, pa);
739     }
740 }
741
742 static void pr_html_files(FILE *out, int nfile, t_filenm fnm[],
743                           const char *program, t_linkdata *links)
744 {
745     int  i;
746     char link[10], tmp[255];
747
748     fprintf(out,
749             "<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=2>\n"
750             "<TR>"
751             "<TH>option</TH>"
752             "<TH>filename</TH>"
753             "<TH>type</TH>"
754             "<TH>description</TH>"
755             "</TR>\n");
756
757     for (i = 0; (i < nfile); i++)
758     {
759         strcpy(link, ftp2ext(fnm[i].ftp));
760         if (strcmp(link, "???") == 0)
761         {
762             strcpy(link, "files");
763         }
764         fprintf(out,
765                 "<TR>"
766                 "<TD ALIGN=RIGHT> <b><tt>%s</tt></b> </TD>"
767                 "<TD ALIGN=RIGHT> <tt><a href=\"%s.html\">%12s</a></tt> </TD>"
768                 "<TD> %s </TD>"
769                 "<TD> %s </TD>"
770                 "</TR>\n",
771                 fnm[i].opt, link, fnm[i].fns[0], fileopt(fnm[i].flag, tmp, 255),
772                 NSR(ftp2desc(fnm[i].ftp)));
773     }
774
775     fprintf(out, "</TABLE>\n");
776 }
777
778 static void write_htmlman(FILE *out,
779                           const char *program,
780                           int nldesc, const char **desc,
781                           int nfile, t_filenm *fnm,
782                           int npargs, t_pargs *pa,
783                           int nbug, const char **bugs,
784                           t_linkdata *links)
785 {
786     int  i;
787     char tmp[255];
788
789     fprintf(out, "<HTML>\n<HEAD>\n<TITLE>%s</TITLE>\n", program);
790     fprintf(out, "<LINK rel=stylesheet href=\"style.css\" type=\"text/css\">\n");
791     fprintf(out, "<BODY text=\"#000000\" bgcolor=\"#FFFFFF\" link=\"#0000FF\" vlink=\"#990000\" alink=\"#FF0000\">\n");
792     fprintf(out, "<TABLE WIDTH=\"98%%\" NOBORDER >\n<TR><TD WIDTH=400>\n");
793     fprintf(out, "<TABLE WIDTH=400 NOBORDER>\n<TD WIDTH=116>\n");
794     fprintf(out, "<a href=\"http://www.gromacs.org/\">"
795             "<img SRC=\"../images/gmxlogo_small.png\""
796             "BORDER=0 </a></td>\n");
797     fprintf(out, "<td ALIGN=LEFT VALIGN=TOP WIDTH=280>"
798             "<br><h2>%s</h2>", program);
799     fprintf(out, "<font size=-1><A HREF=\"../online.html\">Main Table of Contents</A></font><br>");
800     fprintf(out, "<br></td>\n</TABLE></TD><TD WIDTH=\"*\" ALIGN=RIGHT VALIGN=BOTTOM><p><B>%s<br>\n", GromacsVersion());
801     fprintf(out, "%s</B></td></tr></TABLE>\n<HR>\n", mydate(tmp, 255));
802
803     if (nldesc > 0)
804     {
805         fprintf(out, "<H3>Description</H3>\n<p>\n");
806         for (i = 0; (i < nldesc); i++)
807         {
808             fprintf(out, "%s\n", NSR(desc[i]));
809         }
810     }
811     if (nfile > 0)
812     {
813         fprintf(out, "<P>\n");
814         fprintf(out, "<H3>Files</H3>\n");
815         pr_html_files(out, nfile, fnm, program, links);
816     }
817     if (npargs > 0)
818     {
819         fprintf(out, "<P>\n");
820         fprintf(out, "<H3>Other options</H3>\n");
821         fprintf(out,
822                 "<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=2>\n"
823                 "<TR>"
824                 "<TH>option</TH>"
825                 "<TH>type</TH>"
826                 "<TH>default</TH>"
827                 "<TH>description</TH>"
828                 "</TR>\n");
829         for (i = 0; (i < npargs); i++)
830         {
831             fprintf(out,
832                     "<TR>"
833                     "<TD ALIGN=RIGHT> <b><tt>%s%s</tt></b> </TD>"
834                     "<TD ALIGN=RIGHT> %s </TD>"
835                     "<TD ALIGN=RIGHT> <tt>%s</tt> </TD>"
836                     "<TD> %s </TD>"
837                     "</TD>\n",
838                     (pa[i].type == etBOOL) ? "-[no]" : "-", pa[i].option+1,
839                     get_arg_desc(pa[i].type), pa_val(&(pa[i]), tmp, 255), NSR(pa[i].desc));
840         }
841         fprintf(out, "</TABLE>\n");
842     }
843     if (nbug > 0)
844     {
845         fprintf(out, "<P>\n");
846         fprintf(out, "<H3>Known problems</H3>\n");
847         fprintf(out, "<UL>\n");
848         for (i = 0; (i < nbug); i++)
849         {
850             fprintf(out, "<LI>%s\n", NSR(bugs[i]));
851         }
852         fprintf(out, "</UL>\n");
853     }
854     fprintf(out, "<P>\n");
855     fprintf(out, "<hr>\n<div ALIGN=RIGHT>\n");
856     fprintf(out, "<font size=\"-1\"><a href=\"http://www.gromacs.org\">"
857             "http://www.gromacs.org</a></font><br>\n");
858     fprintf(out, "<font size=\"-1\"><a href=\"mailto:gromacs@gromacs.org\">"
859             "gromacs@gromacs.org</a></font><br>\n");
860     fprintf(out, "</div>\n");
861     fprintf(out, "</BODY>\n");
862 }
863
864 static void pr_opts(FILE *fp,
865                     int nfile,  t_filenm *fnm,
866                     int npargs, t_pargs pa[], int shell)
867 {
868     int i;
869
870     switch (shell)
871     {
872         case eshellCSH:
873             fprintf(fp, " \"c/-/(");
874             for (i = 0; i < nfile; i++)
875             {
876                 fprintf(fp, " %s", fnm[i].opt+1);
877             }
878             for (i = 0; i < npargs; i++)
879             {
880                 if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
881                 {
882                     fprintf(fp, " no%s", pa[i].option+1);
883                 }
884                 else
885                 {
886                     fprintf(fp, " %s", pa[i].option+1);
887                 }
888             }
889             fprintf(fp, ")/\"");
890             break;
891         case eshellBASH:
892             fprintf(fp, "if (( $COMP_CWORD <= 1 )) || [[ $c == -* ]]; then COMPREPLY=( $(compgen  -W '");
893             for (i = 0; i < nfile; i++)
894             {
895                 fprintf(fp, " -%s", fnm[i].opt+1);
896             }
897             for (i = 0; i < npargs; i++)
898             {
899                 if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
900                 {
901                     fprintf(fp, " -no%s", pa[i].option+1);
902                 }
903                 else
904                 {
905                     fprintf(fp, " -%s", pa[i].option+1);
906                 }
907             }
908             fprintf(fp, "' -- $c)); return 0; fi\n");
909             break;
910         case eshellZSH:
911             fprintf(fp, " -x 's[-]' -s \"");
912             for (i = 0; i < nfile; i++)
913             {
914                 fprintf(fp, " %s", fnm[i].opt+1);
915             }
916             for (i = 0; i < npargs; i++)
917             {
918                 if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
919                 {
920                     fprintf(fp, " no%s", pa[i].option+1);
921                 }
922                 else
923                 {
924                     fprintf(fp, " %s", pa[i].option+1);
925                 }
926             }
927             fprintf(fp, "\" ");
928             break;
929     }
930 }
931
932 static void write_cshcompl(FILE *out,
933                            int nfile,  t_filenm *fnm,
934                            int npargs, t_pargs *pa)
935 {
936     fprintf(out, "complete %s", ShortProgram());
937     pr_enums(out, npargs, pa, eshellCSH);
938     pr_fopts(out, nfile, fnm, eshellCSH);
939     pr_opts(out, nfile, fnm, npargs, pa, eshellCSH);
940     fprintf(out, "\n");
941 }
942
943 static void write_zshcompl(FILE *out,
944                            int nfile,  t_filenm *fnm,
945                            int npargs, t_pargs *pa)
946 {
947     fprintf(out, "compctl ");
948
949     /* start with options, since they are always present */
950     pr_opts(out, nfile, fnm, npargs, pa, eshellZSH);
951     pr_enums(out, npargs, pa, eshellZSH);
952     pr_fopts(out, nfile, fnm, eshellZSH);
953     fprintf(out, "-- %s\n", ShortProgram());
954 }
955
956 static void write_bashcompl(FILE *out,
957                             int nfile,  t_filenm *fnm,
958                             int npargs, t_pargs *pa)
959 {
960     /* Advanced bash completions are handled by shell functions.
961      * p and c hold the previous and current word on the command line.
962      * We need to use extended globbing, so write it in each completion file */
963     fprintf(out, "shopt -s extglob\n");
964     fprintf(out, "_%s_compl() {\nlocal p c\n", ShortProgram());
965     fprintf(out, "COMPREPLY=() c=${COMP_WORDS[COMP_CWORD]} p=${COMP_WORDS[COMP_CWORD-1]}\n");
966     pr_opts(out, nfile, fnm, npargs, pa, eshellBASH);
967     fprintf(out, "case \"$p\" in\n");
968
969     pr_enums(out, npargs, pa, eshellBASH);
970     pr_fopts(out, nfile, fnm, eshellBASH);
971     fprintf(out, "esac }\ncomplete -F _%s_compl %s\n", ShortProgram(), ShortProgram());
972 }
973
974 void write_man(const char *mantp,
975                const char *program,
976                int nldesc, const char **desc,
977                int nfile, t_filenm *fnm,
978                int npargs, t_pargs *pa,
979                int nbug, const char **bugs)
980 {
981     bool        bHidden = false;
982     int         npar;
983     t_pargs    *par;
984
985     t_linkdata *links;
986
987     links = init_linkdata();
988
989     const gmx::CommandLineHelpContext *context
990         = gmx::GlobalCommandLineHelpContext::get();
991     bool  bFileOpened = false;
992     FILE *out;
993     if (context != NULL)
994     {
995         out     = context->writerContext().outputFile().handle();
996         bHidden = context->showHidden();
997     }
998     else
999     {
1000         char buf[256];
1001         sprintf(buf, "%s.%s", program, mantp);
1002         out         = gmx_fio_fopen(buf, "w");
1003         bFileOpened = true;
1004     }
1005
1006     if (bHidden)
1007     {
1008         npar = npargs;
1009         par  = pa;
1010     }
1011     else
1012     {
1013         snew(par, npargs);
1014         npar = 0;
1015         for (int i = 0; i < npargs; i++)
1016         {
1017             if (!is_hidden(&pa[i]))
1018             {
1019                 par[npar] = pa[i];
1020                 npar++;
1021             }
1022         }
1023     }
1024
1025     if (strcmp(mantp, "tex") == 0)
1026     {
1027         write_texman(out, program, nldesc, desc, nfile, fnm, npar, par, nbug, bugs, links);
1028     }
1029     if (strcmp(mantp, "nroff") == 0)
1030     {
1031         write_nroffman(out, context->moduleDisplayName(), nldesc, desc,
1032                        nfile, fnm, npar, par, nbug, bugs, links);
1033     }
1034     if (strcmp(mantp, "help") == 0)
1035     {
1036         write_ttyman(out, program, nldesc, desc, nfile, fnm, npar, par, nbug, bugs, links);
1037     }
1038     if (strcmp(mantp, "html") == 0)
1039     {
1040         write_htmlman(out, program, nldesc, desc, nfile, fnm, npar, par, nbug, bugs, links);
1041     }
1042     if (strcmp(mantp, "completion-zsh") == 0)
1043     {
1044         write_zshcompl(out, nfile, fnm, npar, par);
1045     }
1046     if (strcmp(mantp, "completion-bash") == 0)
1047     {
1048         write_bashcompl(out, nfile, fnm, npar, par);
1049     }
1050     if (strcmp(mantp, "completion-csh") == 0)
1051     {
1052         write_cshcompl(out, nfile, fnm, npar, par);
1053     }
1054
1055     if (bFileOpened)
1056     {
1057         gmx_fio_fclose(out);
1058     }
1059
1060     if (!bHidden)
1061     {
1062         sfree(par);
1063     }
1064
1065     finish_linkdata(links);
1066 }
1067
1068 const char *get_arg_desc(int type)
1069 {
1070     static const char *argtp[etNR] = {
1071         "int", "step", "real", "time", "string", "bool", "vector", "enum"
1072     };
1073     return argtp[type];
1074 }