1 /*-------------- Telecommunications & Signal Processing Lab ---------------
2 McGill University
3
4 Routine:
5 int UTgetOption (int *Index, int argc, const char *argv[],
6 const char *OptTable[], const char *OptArg[])
7
8 Purpose:
9 Decode command line options and arguments
10
11 Description:
12 This routine decodes command line options, returning option values and other
13 (non-option) argument strings. Typically this routine is used to decode Unix
14 style command options and to return argument strings. An example of a Unix
15 command line is as follows.
16 command -x -f name --delay=30 argA argB.
17 Each of the items in the command line, including the command itself, appears
18 in an array of strings. This routine compares the elements of the command
19 line after the command name for a match to a table of option keywords.
20 Options normally have a leading "-" character.
21
22 The table of keywords contains entries which can specify the minimum length
23 needed for a match with an optional "*" character.
24 -d
25 This form specifies that an exact match to "-d" is required. The "-"
26 character is just treated as an ordinary character for the match.
27 --d*elay
28 This form specifies that the option must match the first three characters
29 and optionally match additional characters. For instance, "--d" matches
30 as does "--del", but not "--dx".
31
32 The need for an option value is signalled in two ways.
33 -d#
34 The presence of the trailing "#" indicates that the option can either
35 directly follow the option as in "-d30" or in the next argument as in
36 "-d" followed by "30" in the next argument.
37 --d*elay=
38 The presence of the trailing "=" indicates that the option can either
39 follow the option, separated by a '=' character as in "--del=30" or in
40 the next argument as in "--del" followed by "30" in the next argument.
41
42 The keywords are searched in order. Keywords can contain a second asterisk
43 can be used to indicate that characters after this point need not match.
44
45 Errors detected by this routine result in an error message being printed and
46 an error code being returned.
47 Invalid option:
48 If all keywords in the list of option keywords start with a "-"
49 character, then any argument with a leading "-", followed by one or
50 more characters and not matching any of the options causes an error
51 condition. This means that ordinary arguments (non-option) cannot start
52 with a "-" if the first option keyword starts with a "-".
53 Missing option value:
54 If an option requires a value, and none is supplied, an error is
55 reported. Such an error can only happen if the option is the last item
56 in the list of arguments, since in other cases the item after the option
57 will be picked up as the option value.
58
59 The results of the option scan are communicated to the calling program via
60 the pointer OptArg. OptArg is a pointer to a pointer to a null terminated
61 strings (substrings of the strings in argv). The interpretation of these
62 strings is given by the return code. When this routine is called in a
63 loop, the OptArg strings are returned in the same order as the options and
64 arguments appeared in argv. The OptArg pointer can be NULL. This is the
65 case for an option with no option value. Each call to UTgetOption returns
66 at most one option or argument.
67
68 Return codes:
69 -2 - Error detected, invalid option or missing value
70 -1 - Normal end of processing
71 0 - Argument string, not an option.
72 n - Option specified by the n'th keyword, n >= 1.
73 For the non-negative return codes, the argument string or the option value
74 string are pointed to by OptArg. OptArg will be NULL for an option for which
75 no option value is allowed.
76
77 The use of this routine is illustrated in the following program fragment.
78 static const char *OptTable[] = {
79 "-d#", "--d*elay=",
80 "-p", "--p*rint",
81 NULL};
82
83 void main (int argc, const char *argv[])
84 {
85 const char *OptArg;
86 int Index;
87 int n;
88
89 Index = 1;
90 while (Index < argc) {
91 n = UTgetOption (&Index, argc, argv, OptTable, &OptArg);
92 switch (n) {
93 case 0:
94 ... process non-option OptArg
95 break;
96 case 1:
97 case 2:
98 ... process option 1 (-d or --delay)
99 break;
100 case 3:
101 case 4:
102 ... process option 2 (-p or --print)
103 break;
104 default:
105 ... error
106 }
107 }
108 }
109
110 Parameters:
111 <- int UTgetOptions
112 Status code,
113 -2 - Error, invalid option or missing value
114 -1 - End of arguments/options
115 0 - Argument value
116 >=1 - Option code
117 <-> int *Index
118 Integer used internally for saving the state of the search. It is the
119 index of the next element of argv to be examined. This value should be
120 saved from call to call. Note that the index may be incremented by zero
121 (error detected), one or two (option followed by a value in the next
122 element of argv). The initial value of Index should be one.
123 -> int argc
124 Number of argument strings in argv
125 -> const char *argv[]
126 Pointers to option/argument strings. Note that with ANSI C, if the
127 actual parameter is not declared to have the const attribute, an explicit
128 cast to (const char **) is required.
129 -> const char *OptTable[]
130 Pointers to the option keywords. The end of the keyword table is
131 signalled by a NULL pointer. Note that with ANSI C, if the actual
132 parameter is not declared to have the const attribute, an explicit cast
133 to (const char **) is required.
134 <- const char *OptArg[]
135 Argument/option string. For an argument or an option taking a value,
136 this is a pointer to a null terminated substring string in argv. If the
137 decoded option does not take a value, this pointer will be NULL. Note
138 that with ANSI C, if the actual parameter is not declared to have the
139 const attribute, an explict cast to (const char **) is required.
140
141 Author / revision:
142 P. Kabal Copyright (C) 2003
143 $Revision: 1.31 $ $Date: 2003/05/09 03:20:37 $
144
145 -------------------------------------------------------------------------*/
146
147 #include <libtsp.h>
148 #include <libtsp/nucleus.h>
149 #include <libtsp/UTmsg.h>
150
151 #define NOMATCH 0
152 #define MATCH 1
153 #define MVAL -2
154
155 #define RET_ERROR -2
156 #define RET_END -1
157 #define RET_ARG 0
158
159
160 int
UTgetOption(int * Index,const int argc,const char * argv[],const char * OptTable[],const char ** OptArg)161 UTgetOption (int *Index, const int argc, const char *argv[],
162 const char *OptTable[], const char **OptArg)
163
164 {
165 int n, status, ip, rv, allminus;
166
167 if (*Index <= 0)
168 ip = 1;
169 else
170 ip = *Index;
171
172 /* Check the index, return if finished processing arguments from argv */
173 if (ip >= argc) {
174 /* Finished processing */
175 *OptArg = NULL;
176 return RET_END;
177 }
178
179 /* Decode the option */
180 rv = NOMATCH;
181 allminus = (OptTable[0] != NULL);
182 for (n = 0; OptTable[n] != NULL; ++n) {
183 if (OptTable[n][0] != '-')
184 allminus = 0;
185 rv = UTdecOption (argv[ip], OptTable[n], OptArg);
186 if (rv != NOMATCH)
187 goto Match;
188 }
189
190 /* Not an option */
191 if (allminus && argv[ip][0] == '-' && argv[ip][1] != '\0') {
192 /* The argument has a leading '-' */
193 UTwarn ("UTgetOption - %s: \"%s\"", UTM_BadOption, argv[ip]);
194 *OptArg = NULL;
195 status = RET_ERROR;
196 }
197 else {
198 /* Ordinary argument */
199 *OptArg = argv[ip];
200 status = RET_ARG;
201 }
202
203 *Index = ip + 1;
204 return status;
205
206 /* ===================== */
207 /* Found an option match */
208 Match:
209 if (rv == MATCH)
210 /* Found an option match */
211 status = n+1;
212
213 else {
214 /* Error - missing value */
215 /* Try to pick up the option from the next argument */
216 if (ip+1 < argc) {
217 ++ip; /* extra increment */
218 *OptArg = argv[ip];
219 status = n+1;
220 }
221 else {
222 UTwarn ("UTgetOption - %s \"%s\"", UTM_ExpectValue, argv[ip]);
223 status = RET_ERROR;
224 }
225 }
226
227 /* Update for next call */
228 *Index = ip + 1;
229 return status;
230 }
231