initial commit
[jalview.git] / forester / archive / RIO / others / hmmer / squid / getopt.c
1 /*****************************************************************
2  * HMMER - Biological sequence analysis with profile HMMs
3  * Copyright (C) 1992-1999 Washington University School of Medicine
4  * All Rights Reserved
5  * 
6  *     This source code is distributed under the terms of the
7  *     GNU General Public License. See the files COPYING and LICENSE
8  *     for details.
9  *****************************************************************/
10
11 /* RCS $Id: getopt.c,v 1.1.1.1 2005/03/22 08:34:26 cmzmasek Exp $
12  */
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17
18 #include "squid.h"
19
20 /* Function: Getopt()
21  * 
22  * Purpose:  Portable command line option parsing with abbreviated
23  *           option switches. Replaces UNIX getopt(). Using UNIX getopt()
24  *           hinders portability to non-UNIX platforms, and getopt()
25  *           is also limited to single letter options.
26  *
27  *           Getopt() implements a superset of UNIX getopt().
28  *           All of getopt()'s single-character switch behavior
29  *           is emulated, and "--" by itself terminates the options.
30  *           Additionally, Getopt() provides extended switches
31  *           like "--youroptionhere", and Getopt() type checks
32  *           arguments.  
33  * 
34  *           Extended options must start with "--", as in "--option1".
35  *           Normal options must start with "-", as in "-o".
36  *           Normal options may be concatenated, as in "-a -b" == "-ab".
37  *           
38  *           See bottom of this .c file after #fdef GETOPT_TESTDRIVER
39  *           for an example of calling Getopt().
40  *           
41  * Args:     argc  - from main(). number of elems in argv.
42  *           argv  - from main(). argv[0] is the name of the command.
43  *           opt   - array of opt_s structures, defining option switches
44  *           nopts - number of switches in opt
45  *           usage - a (possibly long) string to print if usage error.
46  *           ret_optind - RETURN: the index in argv[] of the next 
47  *                        valid command-line token.
48  *           ret_optname- RETURN: ptr to the name of option switch 
49  *                        seen, or NULL if no option was seen.
50  *           ret_optarg - RETURN: ptr to the optional argument, if any;
51  *                        NULL if option takes no argument.
52  *                        
53  * Return:   1 if a valid option was parsed.
54  *           0 if no option was found, and command-line parsing is complete.
55  *           Die()'s here if an error is detected.
56  */
57 int
58 Getopt(int argc, char **argv, struct opt_s *opt, int nopts, char *usage,
59        int *ret_optind, char **ret_optname, char **ret_optarg)
60 {
61   int i;
62   int arglen;
63   int nmatch;
64   static int optind   = 1;        /* init to 1 on first call  */
65   static char *optptr = NULL;     /* ptr to next valid switch */
66   int opti = 0;                   /* init only to silence gcc uninit warnings */
67
68   /* Check to see if we've run out of options.
69    * A '-' by itself is an argument (e.g. "read from stdin")
70    * not an option.
71    */
72   if (optind >= argc || argv[optind][0] != '-' || strcmp(argv[optind], "-") == 0)
73     { 
74       *ret_optind  = optind; 
75       *ret_optarg  = NULL; 
76       *ret_optname = NULL; 
77       return 0; 
78     }
79
80   /* Check to see if we're being told that this is the end
81    * of the options with the special "--" flag.
82    */
83   if (strcmp(argv[optind], "--") == 0)
84     { 
85       optind++;
86       *ret_optind  = optind; 
87       *ret_optname = NULL;
88       *ret_optarg  = NULL; 
89       return 0; 
90     }
91
92   /* We have a real option. Find which one it is.
93    * We handle single letter switches "-o" separately
94    * from full switches "--option", based on the "-" vs. "--"
95    * prefix -- single letter switches can be concatenated
96    * as long as they don't have arguments.
97    */
98                                 /* full option */
99   if (optptr == NULL && strncmp(argv[optind], "--", 2) == 0)
100     {
101       /* Use optptr to parse argument in options of form "--foo=666"
102        */
103       if ((optptr = strchr(argv[optind], '=')) != NULL)
104         { *optptr = '\0'; optptr++; }
105
106       arglen = strlen(argv[optind]);
107       nmatch = 0;
108       for (i = 0; i < nopts; i++)
109         if (opt[i].single == FALSE && 
110             strncmp(opt[i].name, argv[optind], arglen) == 0)
111           { 
112             nmatch++;
113             opti = i;
114             if (arglen == strlen(opt[i].name)) break; /* exact match, stop now */
115           }
116       if (nmatch > 1 && arglen != strlen(opt[i].name)) 
117         Die("Option \"%s\" is ambiguous; please be more specific.\n%s",
118             argv[optind], usage);
119       if (nmatch == 0)
120         Die("No such option \"%s\".\n%s", argv[optind], usage);
121
122       *ret_optname = opt[opti].name;
123
124       /* Set the argument, if there is one
125        */
126       if (opt[opti].argtype != sqdARG_NONE) 
127         {
128           if (optptr != NULL)
129             {                   /* --foo=666 style */
130               *ret_optarg = optptr;
131               optptr = NULL;
132               optind++;
133             }
134           else if (optind+1 >= argc)
135             Die("Option %s requires an argument\n%s", opt[opti].name, usage);
136           else                  /* "--foo 666" style */
137             {
138               *ret_optarg = argv[optind+1];
139               optind+=2;
140             }
141         }
142       else  /* sqdARG_NONE */
143         {
144           if (optptr != NULL) 
145             Die("Option %s does not take an argument\n%s", opt[opti].name, usage);
146           *ret_optarg = NULL;
147           optind++;
148         }
149     }
150   else                          /* else, a single letter option "-o" */
151     {
152                                 /* find the option */
153       if (optptr == NULL) 
154         optptr = argv[optind]+1;
155       for (opti = -1, i = 0; i < nopts; i++)
156         if (opt[i].single == TRUE && *optptr == opt[i].name[1])
157           { opti = i; break; }
158       if (opti == -1)
159         Die("No such option \"%c\".\n%s", *optptr, usage);
160       *ret_optname = opt[opti].name;
161
162                                 /* set the argument, if there is one */
163       if (opt[opti].argtype != sqdARG_NONE) 
164         {
165           if (*(optptr+1) != '\0')   /* attached argument */
166             {
167               *ret_optarg = optptr+1;
168               optind++;
169             }
170           else if (optind+1 < argc) /* unattached argument */
171             {
172               *ret_optarg = argv[optind+1];
173               optind+=2;              
174             }
175           else Die("Option %s requires an argument\n%s", opt[opti].name, usage);
176
177           optptr = NULL;        /* can't concatenate after an argument */
178         }
179       else  /* sqdARG_NONE */
180         {
181           *ret_optarg = NULL;
182           if (*(optptr+1) != '\0')   /* concatenation */
183             optptr++; 
184           else
185             {
186               optind++;                /* move to next field */
187               optptr = NULL;
188             }
189         }
190
191     }
192
193   /* Type check the argument, if there is one
194    */
195   if (opt[opti].argtype != sqdARG_NONE) 
196     {
197       if (opt[opti].argtype == sqdARG_INT && ! IsInt(*ret_optarg))
198         Die("Option %s requires an integer argument\n%s",
199             opt[opti].name, usage);
200       else if (opt[opti].argtype == sqdARG_FLOAT && ! IsReal(*ret_optarg))
201         Die("Option %s requires a numerical argument\n%s",
202             opt[opti].name, usage);
203       else if (opt[opti].argtype == sqdARG_CHAR && strlen(*ret_optarg) != 1)
204         Die("Option %s requires a single-character argument\n%s",
205             opt[opti].name, usage);
206       /* sqdARG_STRING is always ok, no type check necessary */
207     }
208
209   *ret_optind = optind;
210   return 1;
211 }
212
213
214
215 #ifdef GETOPT_TESTDRIVER 
216 /* cc -DGETOPT_TESTDRIVER -L ~/lib/squid.linux/ getopt.c -lsquid
217  */
218 struct opt_s OPTIONS[] = {
219   { "--test1", FALSE, sqdARG_INT    },
220   { "--test2", FALSE, sqdARG_FLOAT  },
221   { "--test3", FALSE, sqdARG_STRING },
222   { "--test4", FALSE, sqdARG_CHAR   },
223   { "-a",      TRUE,  sqdARG_NONE   },
224   { "-b",      TRUE,  sqdARG_INT    },
225 };
226 #define NOPTIONS (sizeof(OPTIONS) / sizeof(struct opt_s))
227     
228 int
229 main(int argc, char **argv)
230 {
231   int   optind;
232   char *optarg;
233   char *optname;
234
235   while (Getopt(argc, argv, OPTIONS, NOPTIONS, "Usage/help here",
236                 &optind, &optname, &optarg))
237     {
238       printf("Option:   index: %d name: %s argument: %s\n",
239              optind, optname, optarg);
240     }
241   while (optind < argc)
242     {
243       printf("Argument: index: %d name: %s\n", optind, argv[optind]);
244       optind++;
245     }
246
247
248 }
249
250
251 #endif /*GETOPT_TESTDRIVER*/