1 /* ncbiargs.c
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * File Name: ncbiargs.c
27 *
28 * Author: Ostell, Schuler, Vakatov
29 *
30 * Version Creation Date: 07/15/91
31 *
32 * File Description:
33 * GetArgs() for console applications
34 *
35 * Modifications:
36 * --------------------------------------------------------------------------
37 * $Log: ncbiargs.c,v $
38 * Revision 6.12 2009/08/17 19:42:08 lavr
39 * Formatting
40 *
41 * Revision 6.11 2009/08/14 18:01:09 lavr
42 * Use {Get|Set}ProgramName()
43 *
44 * Revision 6.10 2006/10/19 14:57:03 lavr
45 * Fix repetitive arg error message to show no argument value since it's empty
46 *
47 * Revision 6.9 2006/10/18 19:15:43 lavr
48 * Allow repetitive (boolean) flags to increment arg's intvalue [spec.cased]
49 *
50 * Revision 6.8 2004/04/01 13:43:06 lavr
51 * Spell "occurred", "occurrence", and "occurring"
52 *
53 * Revision 6.7 2002/11/06 21:22:32 ucko
54 * Accept "--help" as a synonym for the less intuitive "-"
55 *
56 * Revision 6.6 2001/07/03 20:03:11 juran
57 * Don't corruptly parse argv in Mac OS.
58 *
59 * Revision 6.5 2000/06/15 20:51:41 vakatov
60 * Use "const" in Args code
61 *
62 * Revision 6.4 1999/03/11 21:12:23 vakatov
63 * Get in-sync the "printf"/"scanf"'s format and args in some places
64 *
65 * Revision 6.3 1998/01/21 20:55:43 vakatov
66 * Nlm_GetArgs(): fixed memory leak(in the override of default str value)
67 *
68 * Revision 6.2 1997/10/29 02:43:14 vakatov
69 * Type castings to pass through the C++ compiler
70 *
71 * Revision 6.1 1997/10/27 22:00:43 vakatov
72 * Check for the Bool, Int and Float arg. value validity; reset all
73 * arguments if an error occurred
74 *
75 * Revision 5.1 1997/07/22 19:06:56 vakatov
76 * Initial revision: merged GetArgs()'s from former "ncbiargs.msw" and
77 * "ncbimain.[msw,unx,mac,vms]"
78 *
79 * ==========================================================================
80 */
81
82 #include <ncbi.h>
83
84 /*****************************************************************************
85 *
86 * Nlm_GetArgs(ap)
87 * returns user startup arguments
88 *
89 *****************************************************************************/
90
Nlm_GetArgs(const char * progname,Nlm_Int2 numargs,Nlm_ArgPtr ap)91 NLM_EXTERN Nlm_Boolean Nlm_GetArgs(const char* progname,
92 Nlm_Int2 numargs, Nlm_ArgPtr ap)
93 {
94 static const char* types[] = {
95 NULL,
96 "T/F",
97 "Integer",
98 "Real",
99 "String",
100 "File In",
101 "File Out",
102 "Data In",
103 "Data Out"
104 };
105
106 Nlm_Boolean okay, all_default = TRUE, range;
107 Nlm_Int2 i, j;
108 Nlm_ArgPtr curarg;
109 Nlm_Boolean* resolved;
110 Nlm_Int4 xx_argc = Nlm_GetArgc();
111 char** xx_argv = Nlm_GetArgv();
112
113 if (StringHasNoText(GetProgramName()))
114 SetProgramName(progname);
115
116 if (!ap || numargs <= 0)
117 return FALSE;
118
119 resolved = (Nlm_Boolean*) Nlm_MemNew(numargs * sizeof(Nlm_Boolean));
120 if ( !resolved )
121 return FALSE;
122
123 /* reset all args */
124 curarg = ap;
125 for (i = 0; i < numargs; i++, curarg++) {
126 curarg->intvalue = 0;
127 curarg->floatvalue = 0.0;
128 curarg->strvalue = NULL;
129 }
130
131 /* set defaults */
132 curarg = ap;
133 for (i = 0; i < numargs; i++, curarg++)
134 {
135 if ((curarg->type < ARG_BOOLEAN) ||
136 (curarg->type > ARG_DATA_OUT))
137 {
138 ErrPostEx(SEV_ERROR, 0,0, "Invalid Arg->type in %s", curarg->prompt);
139 Nlm_MemFree( resolved );
140 Nlm_FreeArgs(i, ap);
141 return FALSE;
142 }
143 curarg->intvalue = 0;
144 curarg->floatvalue = 0.0;
145 curarg->strvalue = NULL;
146 if (curarg->defaultvalue)
147 {
148 resolved[i] = TRUE;
149 switch (curarg->type)
150 {
151 case ARG_BOOLEAN:
152 if (TO_UPPER(*curarg->defaultvalue) == 'T')
153 curarg->intvalue = 1;
154 else
155 curarg->intvalue = 0;
156 break;
157 case ARG_INT:
158 curarg->intvalue = atol(curarg->defaultvalue);
159 break;
160 case ARG_FLOAT:
161 curarg->floatvalue = atof(curarg->defaultvalue);
162 break;
163 case ARG_STRING:
164 case ARG_FILE_IN:
165 case ARG_FILE_OUT:
166 case ARG_DATA_IN:
167 case ARG_DATA_OUT:
168 curarg->strvalue = StringSave(curarg->defaultvalue);
169 break;
170 }
171 }
172 else if (curarg->optional == FALSE)
173 all_default = FALSE; /* must have some arguments */
174 }
175
176 /**** show usage if no args on command line ***/
177 if (xx_argc == 1 && all_default) /* no args ok */
178 {
179 Nlm_MemFree( resolved );
180 return TRUE;
181 }
182
183 if (xx_argc == 1 || *(xx_argv[1]+1) == '\0'
184 || !strcmp(xx_argv[1], "--help"))
185 {
186 printf("\n%s arguments:\n\n", progname);
187 curarg = ap;
188
189 for (i = 0, j = 0; i < numargs; i++, j++, curarg++)
190 {
191 printf(" -%c %s [%s]", curarg->tag, curarg->prompt,
192 types[curarg->type]);
193 if (curarg->optional)
194 printf(" Optional");
195 printf("\n");
196 if (curarg->defaultvalue)
197 printf(" default = %s\n", curarg->defaultvalue);
198 if (curarg->from || curarg->to)
199 {
200 if (curarg->type == ARG_DATA_IN ||
201 curarg->type == ARG_DATA_OUT)
202 printf(" Data Type = %s\n", curarg->from);
203 else if (curarg->type == ARG_BOOLEAN ||
204 curarg->type == ARG_INT ||
205 curarg->type == ARG_FLOAT)
206 {
207 printf(" range from %s to %s\n",
208 (curarg->from ? curarg->from: "?"),
209 (curarg->to ? curarg->to : "?"));
210 }
211 }
212 }
213
214 printf("\n");
215 fflush (stdout);
216 Nlm_MemFree( resolved );
217 Nlm_FreeArgs(numargs, ap);
218 #ifdef COMP_MPW
219 Message(MSG_OK, "To exit: ");
220 #endif
221 return FALSE;
222 }
223
224
225 /* Parse the arguments */
226 for (i = 1; i < xx_argc; i++)
227 {
228 const char* arg = xx_argv[i];
229 if (*arg != '-')
230 {
231 ErrPostEx(SEV_ERROR, 0, 0, "Arguments must start with '-' (the offending argument #%d was: '%s')", (int)i, arg);
232 Nlm_MemFree( resolved );
233 Nlm_FreeArgs(numargs, ap);
234 return FALSE;
235 }
236 arg++;
237 curarg = ap;
238 for (j = 0; j < numargs; j++, curarg++)
239 {
240 if (*arg == curarg->tag)
241 break;
242 }
243 if (j == numargs)
244 {
245 ErrPostEx(SEV_ERROR, 0, 0, "Invalid argument: %s", xx_argv[i]);
246 Nlm_MemFree( resolved );
247 Nlm_FreeArgs(numargs, ap);
248 return FALSE;
249 }
250 arg++;
251
252 if (*arg == '\0')
253 {
254 Nlm_Boolean ok = FALSE;
255 if ((i + 1) < xx_argc) /* argument comes after space */
256 {
257 if (*xx_argv[i + 1] == '-')
258 {
259 char tmp = *(xx_argv[i+1]+1);
260 if ((curarg->type == ARG_INT || curarg->type == ARG_FLOAT)
261 && (tmp == '.' || IS_DIGIT(tmp)))
262 ok = TRUE;
263 }
264 else
265 ok = TRUE;
266
267 if ( ok ) {
268 i++;
269 arg = xx_argv[i];
270 }
271 }
272
273 if (!ok && curarg->type != ARG_BOOLEAN)
274 {
275 ErrPostEx(SEV_ERROR, 0, 0,
276 "No argument value given for %s", curarg->prompt);
277 Nlm_MemFree( resolved );
278 Nlm_FreeArgs(numargs, ap);
279 return FALSE;
280 }
281 }
282
283 resolved[j] = TRUE;
284 switch (curarg->type)
285 {
286 case ARG_BOOLEAN:
287 if (TO_UPPER(*arg) == 'T')
288 curarg->intvalue = 1;
289 else if (TO_UPPER(*arg) == 'F')
290 curarg->intvalue = 0;
291 else if (*arg == '\0')
292 {
293 long idef, ifrom, ito;
294 if (curarg->from && curarg->to &&
295 sscanf(curarg->defaultvalue, "%ld", &idef) > 0 &&
296 sscanf(curarg->from, "%ld", &ifrom) > 0 &&
297 sscanf(curarg->to, "%ld", &ito) > 0 &&
298 idef == 0 && ifrom == 0 && ito > 1)
299 {
300 if (curarg->intvalue >= ito)
301 {
302 ErrPostEx(SEV_ERROR, 0, 0,
303 "%s allowed no more than %s times",
304 curarg->prompt, curarg->to);
305 Nlm_MemFree( resolved );
306 Nlm_FreeArgs(numargs, ap);
307 return FALSE;
308 }
309 else
310 curarg->intvalue++;
311 }
312 else
313 curarg->intvalue = 1;
314 }
315 else
316 {
317 ErrPostEx(SEV_ERROR, 0, 0,
318 "%s [%s] must be one of {'T', 't', 'F', 'f'}"
319 " or omitted", curarg->prompt, arg);
320 Nlm_MemFree( resolved );
321 Nlm_FreeArgs(numargs, ap);
322 return FALSE;
323 }
324 break;
325
326 case ARG_INT: {
327 long val;
328 range = TRUE;
329 if (sscanf(arg, "%ld", &val) <= 0)
330 range = FALSE;
331 curarg->intvalue = val;
332 if (range && curarg->from && curarg->intvalue < atol(curarg->from))
333 {
334 range = FALSE;
335 }
336 if (range && curarg->to && curarg->intvalue > atol(curarg->to))
337 {
338 range = FALSE;
339 }
340 if ( !range )
341 {
342 ErrPostEx(SEV_ERROR, 0, 0,
343 "%s [%s] is bad or out of range [%s to %s]",
344 curarg->prompt, arg,
345 curarg->from ? curarg->from : "?",
346 curarg->to ? curarg->to : "?");
347 Nlm_MemFree( resolved );
348 Nlm_FreeArgs(numargs, ap);
349 return FALSE;
350 }
351 break;
352 }
353
354 case ARG_FLOAT: {
355 double val;
356 range = TRUE;
357 if (sscanf(arg, "%lf", &val) <= 0)
358 range = FALSE;
359 curarg->floatvalue = val;
360 if (range && curarg->from && curarg->floatvalue < atof(curarg->from))
361 {
362 range = FALSE;
363 }
364 if (range && curarg->to && curarg->floatvalue > atof(curarg->to))
365 {
366 range = FALSE;
367 }
368 if ( !range )
369 {
370 ErrPostEx(SEV_ERROR, 0, 0,
371 "%s [%s] is bad or out of range [%s to %s]",
372 curarg->prompt, arg,
373 curarg->from ? curarg->from : "?",
374 curarg->to ? curarg->to : "?");
375 Nlm_MemFree( resolved );
376 Nlm_FreeArgs(numargs, ap);
377 return FALSE;
378 }
379 break;
380 }
381
382 case ARG_STRING:
383 case ARG_FILE_IN:
384 case ARG_FILE_OUT:
385 case ARG_DATA_IN:
386 case ARG_DATA_OUT:
387 if ( curarg->strvalue )
388 MemFree(curarg->strvalue);
389 curarg->strvalue = StringSave(arg);
390 break;
391 } /*** end switch ****/
392 }
393
394 okay = TRUE;
395 curarg = ap;
396 for (i = 0; i < numargs; i++, curarg++)
397 {
398 if (!curarg->optional && !resolved[i])
399 {
400 ErrPostEx(SEV_ERROR, 0, 0,
401 "%s was not given an argument", curarg->prompt);
402 okay = FALSE;
403 }
404 }
405
406 Nlm_MemFree( resolved );
407 if ( !okay )
408 Nlm_FreeArgs(numargs, ap);
409
410 return okay;
411 }
412
413
Nlm_GetArgsSilent(const char * progname,Nlm_Int2 numargs,Nlm_ArgPtr ap)414 NLM_EXTERN Nlm_Boolean Nlm_GetArgsSilent(const char* progname,
415 Nlm_Int2 numargs, Nlm_ArgPtr ap)
416 {
417 return Nlm_GetArgs(progname, numargs, ap);
418 }
419
420