Update copyright statements and change license to LGPL
[alexxy/gromacs.git] / src / gmxlib / pargs.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team,
6  * check out http://www.gromacs.org for more information.
7  * Copyright (c) 2012, by the GROMACS development team, led by
8  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9  * others, as listed in the AUTHORS file in the top-level source
10  * directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38 /* This file is completely threadsafe - keep it that way! */
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #include <stdio.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include "typedefs.h"
47 #include "gmx_fatal.h"
48 #include "statutil.h"
49 #include "readinp.h"
50 #include "smalloc.h"
51 #include "names.h"
52 #include "string2.h"
53 #include "vec.h"
54
55 /* The source code in this file should be thread-safe. 
56       Please keep it that way. */
57
58 gmx_bool is_hidden(t_pargs *pa)
59 {
60   return ((strstr(pa->desc,"HIDDEN") != NULL) || 
61           (strstr(pa->desc,"[hidden]") != NULL));
62 }
63
64 void get_pargs(int *argc,char *argv[],int nparg,t_pargs pa[],gmx_bool bKeepArgs)
65 {
66     int  i,j,k,match;
67     gmx_bool *bKeep;
68     char buf[32];
69     char *ptr;
70
71     snew(bKeep,*argc+1);
72     bKeep[0]     = TRUE;
73     bKeep[*argc] = TRUE;
74
75     for(i=1; (i<*argc); i++) {
76         bKeep[i] = TRUE;
77         for(j=0; (j<nparg); j++) {
78             if (pa[j].type == etBOOL) {
79                 sprintf(buf,"-no%s",pa[j].option+1);
80                 if (strcmp(pa[j].option,argv[i])== 0) {
81                     *pa[j].u.b = TRUE;
82                     pa[j].bSet = TRUE;
83                     bKeep[i] = FALSE;
84                 }
85                 else if (strcmp(buf,argv[i])== 0) {
86                     *pa[j].u.b = FALSE;
87                     pa[j].bSet = TRUE;
88                     bKeep[i] = FALSE;
89                 }
90             } 
91             else if (strcmp(pa[j].option,argv[i])== 0) {
92                 if (pa[j].bSet)
93                     fprintf(stderr,"Setting option %s more than once!\n",
94                             pa[j].option);
95                 pa[j].bSet = TRUE;
96                 bKeep[i] = FALSE;
97                 switch(pa[j].type) {
98                     case etINT:
99                         *pa[j].u.i = iscan(*argc,argv,&i);
100                         break;
101                     case etGMX_LARGE_INT: 
102                         *pa[j].u.is = istepscan(*argc,argv,&i);
103                         break;    
104                     case etTIME:
105                     case etREAL:
106                         *pa[j].u.r = dscan(*argc,argv,&i);
107                         break;
108                     case etSTR:
109                         *(pa[j].u.c) = sscan(*argc,argv,&i);
110                         break;
111                     case etENUM:
112                         match=NOTSET;
113                         ptr = sscan(*argc,argv,&i);
114                         for(k=1; (pa[j].u.c[k] != NULL); k++)
115                             /* only check ptr against beginning of 
116                                pa[j].u.c[k] */
117                             if (gmx_strncasecmp(ptr,pa[j].u.c[k],strlen(ptr)) == 0)
118                                 if ( ( match == NOTSET ) || 
119                                         ( strlen(pa[j].u.c[k]) < 
120                                           strlen(pa[j].u.c[match]) ) )
121                                     match = k;
122                         if (match!=NOTSET)
123                             pa[j].u.c[0] = pa[j].u.c[match];
124                         else 
125                             gmx_fatal(FARGS,"Invalid argument %s for option %s",
126                                     ptr,pa[j].option);
127                         break;
128                     case etRVEC:
129                         (*pa[j].u.rv)[0] = dscan(*argc,argv,&i);
130                         if ( (i+1 == *argc) || 
131                                 ( (argv[i+1][0]=='-') && 
132                                   !isdigit(argv[i+1][1]) ) )
133                             (*pa[j].u.rv)[1] = 
134                             (*pa[j].u.rv)[2] = 
135                             (*pa[j].u.rv)[0];
136                         else {
137                             bKeep[i] = FALSE;
138                             (*pa[j].u.rv)[1] = dscan(*argc,argv,&i);
139                             if ( (i+1 == *argc) || 
140                                     ( (argv[i+1][0]=='-') && 
141                                       !isdigit(argv[i+1][1]) ) )
142                                 gmx_fatal(FARGS,
143                                   "%s: vector must have 1 or 3 real parameters",
144                                         pa[j].option);
145                             bKeep[i] = FALSE;
146                             (*pa[j].u.rv)[2] = dscan(*argc,argv,&i);
147                         }
148                         break;
149                     default:
150                         gmx_fatal(FARGS,"Invalid type %d in pargs",pa[j].type);
151                 }
152                 /* i may be incremented, so set it to not keep */
153                 bKeep[i] = FALSE;
154             }
155         }
156     }
157     if (!bKeepArgs) {
158         /* Remove used entries */
159         for(i=j=0; (i<=*argc); i++) {
160             if (bKeep[i])
161                 argv[j++]=argv[i];
162         }
163         (*argc)=j-1;
164     }
165     sfree(bKeep);
166 }
167
168 int opt2parg_int(const char *option,int nparg,t_pargs pa[])
169 {
170   int i;
171   
172   for(i=0; (i<nparg); i++)
173     if (strcmp(pa[i].option,option) == 0)
174       return *pa[i].u.i;
175   
176   gmx_fatal(FARGS,"No integer option %s in pargs",option);
177   
178   return 0;
179 }
180
181 gmx_bool opt2parg_gmx_bool(const char *option,int nparg,t_pargs pa[])
182 {
183   int i;
184   
185   for(i=0; (i<nparg); i++)
186     if (strcmp(pa[i].option,option) == 0)
187       return *pa[i].u.b;
188   
189   gmx_fatal(FARGS,"No gmx_boolean option %s in pargs",option);
190   
191   return FALSE;
192 }
193
194 real opt2parg_real(const char *option,int nparg,t_pargs pa[])
195 {
196   int i;
197   
198   for(i=0; (i<nparg); i++)
199     if (strcmp(pa[i].option,option) == 0)
200       return *pa[i].u.r;
201   
202   gmx_fatal(FARGS,"No real option %s in pargs",option);
203   
204   return 0.0;
205 }
206
207 const char *opt2parg_str(const char *option,int nparg,t_pargs pa[])
208 {
209   int i;
210   
211   for(i=0; (i<nparg); i++)
212     if (strcmp(pa[i].option,option) == 0)
213       return *(pa[i].u.c);
214   
215   gmx_fatal(FARGS,"No string option %s in pargs",option);
216   
217   return NULL;
218 }
219
220 gmx_bool opt2parg_bSet(const char *option,int nparg,t_pargs pa[])
221 {
222   int i;
223   
224   for(i=0; (i<nparg); i++)
225     if (strcmp(pa[i].option,option) == 0)
226       return pa[i].bSet;
227   
228   gmx_fatal(FARGS,"No such option %s in pargs",option);
229   
230   return FALSE; /* Too make some compilers happy */
231 }
232
233 const char *opt2parg_enum(const char *option,int nparg,t_pargs pa[])
234 {
235   int i;
236   
237   for(i=0; (i<nparg); i++)
238     if (strcmp(pa[i].option,option) == 0)
239       return pa[i].u.c[0];
240   
241   gmx_fatal(FARGS,"No such option %s in pargs",option);
242   
243   return NULL;
244 }
245
246 char *pa_val(t_pargs *pa, char buf[], int sz)
247 {
248   real r;
249   char buf_str[1256]; buf_str[0]='\0';
250
251   buf[0]='\0';
252
253   if(sz<255)
254     gmx_fatal(FARGS,"Buffer must be at least 255 chars\n");
255   
256   switch(pa->type) {
257   case etINT:
258     sprintf(buf,"%-d",*(pa->u.i));
259     break;
260   case etGMX_LARGE_INT:
261     sprintf(buf,gmx_large_int_pfmt,*(pa->u.is));
262     break;      
263   case etTIME:
264   case etREAL:
265     r=*(pa->u.r);
266     sprintf(buf_str,"%-6g",r);
267     strcpy(buf, buf_str);
268     break;
269   case etBOOL:
270     sprintf(buf,"%-6s",*(pa->u.b) ? "yes" : "no");
271     break;
272   case etSTR:
273     if (*(pa->u.c)) {
274       if (strlen(*(pa->u.c)) >= (size_t)sz)
275         gmx_fatal(FARGS,"Argument too long: \"%d\"\n",*(pa->u.c));
276       else
277         strcpy(buf,*(pa->u.c));
278     }
279     break;
280   case etENUM:
281     strcpy(buf,*(pa->u.c));
282     break;
283   case etRVEC:
284     sprintf(buf,"%g %g %g",(*pa->u.rv)[0],
285                            (*pa->u.rv)[1],
286                            (*pa->u.rv)[2]);
287     break;
288   }
289   return buf;
290 }
291
292 #define OPTLEN 12
293 #define TYPELEN 6
294 #define LONGSTR 1024
295 char *pargs_print_line(t_pargs *pa,gmx_bool bLeadingSpace)
296 {
297   char buf[LONGSTR],*buf2,*tmp,*desc;
298
299   snew(buf2,LONGSTR+strlen(pa->desc));
300   snew(tmp,LONGSTR+strlen(pa->desc));
301   
302   if (pa->type == etBOOL)
303     sprintf(buf,"-[no]%s",pa->option+1);
304   else
305     strcpy(buf,pa->option);
306   desc = check_tty(pa->desc);
307   if (strlen(buf)>((OPTLEN+TYPELEN)-max(strlen(argtp[pa->type]),4))) {
308     sprintf(buf2,"%s%s %-6s %-6s  %-s\n",
309             bLeadingSpace ? " " : "",buf,
310             argtp[pa->type],pa_val(pa,tmp,LONGSTR-1),desc);
311   } else if (strlen(buf)>OPTLEN) {
312     /* so type can be 3 or 4 char's, this fits in the %4s */
313     sprintf(buf2,"%s%-14s %-4s %-6s  %-s\n",
314             bLeadingSpace ? " " : "",buf,argtp[pa->type],
315             pa_val(pa,tmp,LONGSTR-1),desc);
316   } else
317     sprintf(buf2,"%s%-12s %-6s %-6s  %-s\n",
318             bLeadingSpace ? " " : "",buf,argtp[pa->type],
319             pa_val(pa,tmp,LONGSTR-1),desc);
320   sfree(desc);
321   sfree(tmp);
322     
323   tmp = wrap_lines(buf2,78,28,FALSE);
324   
325   sfree(buf2);
326   
327   return tmp;
328 }
329
330 void print_pargs(FILE *fp, int npargs,t_pargs pa[],gmx_bool bLeadingSpace)
331 {
332   gmx_bool bShowHidden;
333   char buf[32],buf2[256],tmp[256];
334   char *wdesc;
335   int  i;
336   
337   /* Cannot call opt2parg_bSet here, because it crashes when the option
338    * is not in the list (mdrun)
339    */
340   bShowHidden = FALSE;
341   for(i=0; (i<npargs); i++) 
342     if ((strcmp(pa[i].option,"-hidden")==0) && (pa[i].bSet))
343       bShowHidden = TRUE;
344   
345   if (npargs > 0) {
346     fprintf(fp,"%s%-12s %-6s %-6s  %-s\n",
347             bLeadingSpace ? " " : "","Option","Type","Value","Description");
348     fprintf(fp,"%s------------------------------------------------------\n",
349             bLeadingSpace ? " " : "");
350     for(i=0; (i<npargs); i++) {
351       if (bShowHidden || !is_hidden(&pa[i])) {
352         wdesc = pargs_print_line(&pa[i],bLeadingSpace);
353         fprintf(fp,"%s",wdesc);
354         sfree(wdesc);
355       }
356     }
357     fprintf(fp,"\n");
358   }
359 }
360
361 void pr_enums(FILE *fp, int npargs,t_pargs pa[], int shell)
362 {
363   int i,j;
364
365   switch (shell) {
366   case eshellCSH:
367     for (i=0; i<npargs; i++) 
368       if (pa[i].type==etENUM) {
369         fprintf(fp," \"n/%s/(",pa[i].option);
370         for(j=1; pa[i].u.c[j]; j++)
371           fprintf(fp," %s",pa[i].u.c[j]);
372         fprintf(fp,")/\"");
373       }
374     break;
375   case eshellBASH:
376     for (i=0; i<npargs; i++) 
377       if (pa[i].type==etENUM) {
378         fprintf(fp,"%s) COMPREPLY=( $(compgen -W '",pa[i].option);
379         for(j=1; pa[i].u.c[j]; j++)
380           fprintf(fp," %s",pa[i].u.c[j]);
381         fprintf(fp," ' -- $c ));;\n");
382       }    
383     break;
384   case eshellZSH:
385     for (i=0; i<npargs; i++) 
386       if (pa[i].type==etENUM) {
387         fprintf(fp,"- 'c[-1,%s]' -s \"", pa[i].option);
388         for(j=1; pa[i].u.c[j]; j++)
389           fprintf(fp," %s",pa[i].u.c[j]);
390         fprintf(fp,"\" ");
391       }
392     break;
393   }
394 }
395