4df3a5149496fc2a1d932aa2af3b5a9e0cdcf392
[alexxy/gromacs.git] / src / gmxlib / pargs.c
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 /* This file is completely threadsafe - keep it that way! */
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include <stdio.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include "typedefs.h"
44 #include "gmx_fatal.h"
45 #include "statutil.h"
46 #include "readinp.h"
47 #include "smalloc.h"
48 #include "names.h"
49 #include "string2.h"
50 #include "vec.h"
51
52 /* The source code in this file should be thread-safe. 
53       Please keep it that way. */
54
55 gmx_bool is_hidden(t_pargs *pa)
56 {
57   return ((strstr(pa->desc,"HIDDEN") != NULL) || 
58           (strstr(pa->desc,"[hidden]") != NULL));
59 }
60
61 void get_pargs(int *argc,char *argv[],int nparg,t_pargs pa[],gmx_bool bKeepArgs)
62 {
63     int  i,j,k,match;
64     gmx_bool *bKeep;
65     char buf[32];
66     char *ptr;
67
68     snew(bKeep,*argc+1);
69     bKeep[0]     = TRUE;
70     bKeep[*argc] = TRUE;
71
72     for(i=1; (i<*argc); i++) {
73         bKeep[i] = TRUE;
74         for(j=0; (j<nparg); j++) {
75             if (pa[j].type == etBOOL) {
76                 sprintf(buf,"-no%s",pa[j].option+1);
77                 if (strcmp(pa[j].option,argv[i])== 0) {
78                     *pa[j].u.b = TRUE;
79                     pa[j].bSet = TRUE;
80                     bKeep[i] = FALSE;
81                 }
82                 else if (strcmp(buf,argv[i])== 0) {
83                     *pa[j].u.b = FALSE;
84                     pa[j].bSet = TRUE;
85                     bKeep[i] = FALSE;
86                 }
87             } 
88             else if (strcmp(pa[j].option,argv[i])== 0) {
89                 if (pa[j].bSet)
90                     fprintf(stderr,"Setting option %s more than once!\n",
91                             pa[j].option);
92                 pa[j].bSet = TRUE;
93                 bKeep[i] = FALSE;
94                 switch(pa[j].type) {
95                     case etINT:
96                         *pa[j].u.i = iscan(*argc,argv,&i);
97                         break;
98                     case etGMX_LARGE_INT: 
99                         *pa[j].u.is = istepscan(*argc,argv,&i);
100                         break;    
101                     case etTIME:
102                     case etREAL:
103                         *pa[j].u.r = dscan(*argc,argv,&i);
104                         break;
105                     case etSTR:
106                         *(pa[j].u.c) = sscan(*argc,argv,&i);
107                         break;
108                     case etENUM:
109                         match=NOTSET;
110                         ptr = sscan(*argc,argv,&i);
111                         for(k=1; (pa[j].u.c[k] != NULL); k++)
112                             /* only check ptr against beginning of 
113                                pa[j].u.c[k] */
114                             if (gmx_strncasecmp(ptr,pa[j].u.c[k],strlen(ptr)) == 0)
115                                 if ( ( match == NOTSET ) || 
116                                         ( strlen(pa[j].u.c[k]) < 
117                                           strlen(pa[j].u.c[match]) ) )
118                                     match = k;
119                         if (match!=NOTSET)
120                             pa[j].u.c[0] = pa[j].u.c[match];
121                         else 
122                             gmx_fatal(FARGS,"Invalid argument %s for option %s",
123                                     ptr,pa[j].option);
124                         break;
125                     case etRVEC:
126                         (*pa[j].u.rv)[0] = dscan(*argc,argv,&i);
127                         if ( (i+1 == *argc) || 
128                                 ( (argv[i+1][0]=='-') && 
129                                   !isdigit(argv[i+1][1]) ) )
130                             (*pa[j].u.rv)[1] = 
131                             (*pa[j].u.rv)[2] = 
132                             (*pa[j].u.rv)[0];
133                         else {
134                             bKeep[i] = FALSE;
135                             (*pa[j].u.rv)[1] = dscan(*argc,argv,&i);
136                             if ( (i+1 == *argc) || 
137                                     ( (argv[i+1][0]=='-') && 
138                                       !isdigit(argv[i+1][1]) ) )
139                                 gmx_fatal(FARGS,
140                                   "%s: vector must have 1 or 3 real parameters",
141                                         pa[j].option);
142                             bKeep[i] = FALSE;
143                             (*pa[j].u.rv)[2] = dscan(*argc,argv,&i);
144                         }
145                         break;
146                     default:
147                         gmx_fatal(FARGS,"Invalid type %d in pargs",pa[j].type);
148                 }
149                 /* i may be incremented, so set it to not keep */
150                 bKeep[i] = FALSE;
151             }
152         }
153     }
154     if (!bKeepArgs) {
155         /* Remove used entries */
156         for(i=j=0; (i<=*argc); i++) {
157             if (bKeep[i])
158                 argv[j++]=argv[i];
159         }
160         (*argc)=j-1;
161     }
162     sfree(bKeep);
163 }
164
165 int opt2parg_int(const char *option,int nparg,t_pargs pa[])
166 {
167   int i;
168   
169   for(i=0; (i<nparg); i++)
170     if (strcmp(pa[i].option,option) == 0)
171       return *pa[i].u.i;
172   
173   gmx_fatal(FARGS,"No integer option %s in pargs",option);
174   
175   return 0;
176 }
177
178 gmx_bool opt2parg_gmx_bool(const char *option,int nparg,t_pargs pa[])
179 {
180   int i;
181   
182   for(i=0; (i<nparg); i++)
183     if (strcmp(pa[i].option,option) == 0)
184       return *pa[i].u.b;
185   
186   gmx_fatal(FARGS,"No gmx_boolean option %s in pargs",option);
187   
188   return FALSE;
189 }
190
191 real opt2parg_real(const char *option,int nparg,t_pargs pa[])
192 {
193   int i;
194   
195   for(i=0; (i<nparg); i++)
196     if (strcmp(pa[i].option,option) == 0)
197       return *pa[i].u.r;
198   
199   gmx_fatal(FARGS,"No real option %s in pargs",option);
200   
201   return 0.0;
202 }
203
204 const char *opt2parg_str(const char *option,int nparg,t_pargs pa[])
205 {
206   int i;
207   
208   for(i=0; (i<nparg); i++)
209     if (strcmp(pa[i].option,option) == 0)
210       return *(pa[i].u.c);
211   
212   gmx_fatal(FARGS,"No string option %s in pargs",option);
213   
214   return NULL;
215 }
216
217 gmx_bool opt2parg_bSet(const char *option,int nparg,t_pargs pa[])
218 {
219   int i;
220   
221   for(i=0; (i<nparg); i++)
222     if (strcmp(pa[i].option,option) == 0)
223       return pa[i].bSet;
224   
225   gmx_fatal(FARGS,"No such option %s in pargs",option);
226   
227   return FALSE; /* Too make some compilers happy */
228 }
229
230 const char *opt2parg_enum(const char *option,int nparg,t_pargs pa[])
231 {
232   int i;
233   
234   for(i=0; (i<nparg); i++)
235     if (strcmp(pa[i].option,option) == 0)
236       return pa[i].u.c[0];
237   
238   gmx_fatal(FARGS,"No such option %s in pargs",option);
239   
240   return NULL;
241 }
242
243 char *pa_val(t_pargs *pa, char buf[], int sz)
244 {
245   real r;
246   char buf_str[1256]; buf_str[0]='\0';
247
248   buf[0]='\0';
249
250   if(sz<255)
251     gmx_fatal(FARGS,"Buffer must be at least 255 chars\n");
252   
253   switch(pa->type) {
254   case etINT:
255     sprintf(buf,"%-d",*(pa->u.i));
256     break;
257   case etGMX_LARGE_INT:
258     sprintf(buf,gmx_large_int_pfmt,*(pa->u.is));
259     break;      
260   case etTIME:
261   case etREAL:
262     r=*(pa->u.r);
263     sprintf(buf_str,"%-6g",r);
264     strcpy(buf, buf_str);
265     break;
266   case etBOOL:
267     sprintf(buf,"%-6s",*(pa->u.b) ? "yes" : "no");
268     break;
269   case etSTR:
270     if (*(pa->u.c)) {
271       if (strlen(*(pa->u.c)) >= (size_t)sz)
272         gmx_fatal(FARGS,"Argument too long: \"%d\"\n",*(pa->u.c));
273       else
274         strcpy(buf,*(pa->u.c));
275     }
276     break;
277   case etENUM:
278     strcpy(buf,*(pa->u.c));
279     break;
280   case etRVEC:
281     sprintf(buf,"%g %g %g",(*pa->u.rv)[0],
282                            (*pa->u.rv)[1],
283                            (*pa->u.rv)[2]);
284     break;
285   }
286   return buf;
287 }
288
289 #define OPTLEN 12
290 #define TYPELEN 6
291 #define LONGSTR 1024
292 char *pargs_print_line(t_pargs *pa,gmx_bool bLeadingSpace)
293 {
294   char buf[LONGSTR],*buf2,*tmp,*desc;
295
296   snew(buf2,LONGSTR+strlen(pa->desc));
297   snew(tmp,LONGSTR+strlen(pa->desc));
298   
299   if (pa->type == etBOOL)
300     sprintf(buf,"-[no]%s",pa->option+1);
301   else
302     strcpy(buf,pa->option);
303   desc = check_tty(pa->desc);
304   if (strlen(buf)>((OPTLEN+TYPELEN)-max(strlen(argtp[pa->type]),4))) {
305     sprintf(buf2,"%s%s %-6s %-6s  %-s\n",
306             bLeadingSpace ? " " : "",buf,
307             argtp[pa->type],pa_val(pa,tmp,LONGSTR-1),desc);
308   } else if (strlen(buf)>OPTLEN) {
309     /* so type can be 3 or 4 char's, this fits in the %4s */
310     sprintf(buf2,"%s%-14s %-4s %-6s  %-s\n",
311             bLeadingSpace ? " " : "",buf,argtp[pa->type],
312             pa_val(pa,tmp,LONGSTR-1),desc);
313   } else
314     sprintf(buf2,"%s%-12s %-6s %-6s  %-s\n",
315             bLeadingSpace ? " " : "",buf,argtp[pa->type],
316             pa_val(pa,tmp,LONGSTR-1),desc);
317   sfree(desc);
318   sfree(tmp);
319     
320   tmp = wrap_lines(buf2,78,28,FALSE);
321   
322   sfree(buf2);
323   
324   return tmp;
325 }
326
327 void print_pargs(FILE *fp, int npargs,t_pargs pa[],gmx_bool bLeadingSpace)
328 {
329   gmx_bool bShowHidden;
330   char buf[32],buf2[256],tmp[256];
331   char *wdesc;
332   int  i;
333   
334   /* Cannot call opt2parg_bSet here, because it crashes when the option
335    * is not in the list (mdrun)
336    */
337   bShowHidden = FALSE;
338   for(i=0; (i<npargs); i++) 
339     if ((strcmp(pa[i].option,"-hidden")==0) && (pa[i].bSet))
340       bShowHidden = TRUE;
341   
342   if (npargs > 0) {
343     fprintf(fp,"%s%-12s %-6s %-6s  %-s\n",
344             bLeadingSpace ? " " : "","Option","Type","Value","Description");
345     fprintf(fp,"%s------------------------------------------------------\n",
346             bLeadingSpace ? " " : "");
347     for(i=0; (i<npargs); i++) {
348       if (bShowHidden || !is_hidden(&pa[i])) {
349         wdesc = pargs_print_line(&pa[i],bLeadingSpace);
350         fprintf(fp,"%s",wdesc);
351         sfree(wdesc);
352       }
353     }
354     fprintf(fp,"\n");
355   }
356 }
357
358 void pr_enums(FILE *fp, int npargs,t_pargs pa[], int shell)
359 {
360   int i,j;
361
362   switch (shell) {
363   case eshellCSH:
364     for (i=0; i<npargs; i++) 
365       if (pa[i].type==etENUM) {
366         fprintf(fp," \"n/%s/(",pa[i].option);
367         for(j=1; pa[i].u.c[j]; j++)
368           fprintf(fp," %s",pa[i].u.c[j]);
369         fprintf(fp,")/\"");
370       }
371     break;
372   case eshellBASH:
373     for (i=0; i<npargs; i++) 
374       if (pa[i].type==etENUM) {
375         fprintf(fp,"%s) COMPREPLY=( $(compgen -W '",pa[i].option);
376         for(j=1; pa[i].u.c[j]; j++)
377           fprintf(fp," %s",pa[i].u.c[j]);
378         fprintf(fp," ' -- $c ));;\n");
379       }    
380     break;
381   case eshellZSH:
382     for (i=0; i<npargs; i++) 
383       if (pa[i].type==etENUM) {
384         fprintf(fp,"- 'c[-1,%s]' -s \"", pa[i].option);
385         for(j=1; pa[i].u.c[j]; j++)
386           fprintf(fp," %s",pa[i].u.c[j]);
387         fprintf(fp,"\" ");
388       }
389     break;
390   }
391 }
392