Mercurial > mplayer.hg
annotate subopt-helper.c @ 14369:a98495858305
changes against 1.0 + Dec 2004 SVN math code
author | henry |
---|---|
date | Wed, 05 Jan 2005 09:50:05 +0000 |
parents | 90bcd37dba7f |
children | 00c3c4111017 |
rev | line source |
---|---|
14281 | 1 /** |
2 * \file subopt-helper.c | |
3 * | |
4 * \brief Compensates the suboption parsing code duplication a bit. | |
5 * | |
6 * The routines defined below are there to help you with the | |
7 * suboption parsing. Meaning extracting the options and their | |
8 * values for you and also outputting generic help message if | |
9 * a parse error is encountered. | |
10 * | |
11 * Most stuff happens in the subopt_parse function: if you call it | |
12 * it parses for the passed opts in the passed string. It calls some | |
13 * extra functions for explicit argument parsing ( where the option | |
14 * itself isn't the argument but a value given after the argument | |
15 * delimiter ('='). It also calls your test function if you supplied | |
16 * one. | |
17 * | |
18 */ | |
19 | |
20 #include "subopt-helper.h" | |
21 #include "mp_msg.h" | |
22 | |
23 #include <stdlib.h> | |
24 #include <string.h> | |
25 #include <assert.h> | |
26 | |
27 #ifndef MPDEBUG | |
28 #define NDEBUG | |
29 #endif | |
30 | |
31 /* prototypes for argument parsing */ | |
32 static char const * parse_int( char const * const str, int * const valp ); | |
33 static char const * parse_str( char const * const str, strarg_t * const valp ); | |
34 | |
35 /** | |
36 * \brief Try to parse all options in str and fail if it was not possible. | |
37 * | |
38 * \param str Pointer to the zero terminated string to be parsed. | |
39 * \param opts Pointer to a options array. The array must be terminated | |
40 * with an element having set name to NULL in its opt_t structure. | |
41 * | |
42 * \return The return value is zero if the string could be parsed | |
43 * else a non-zero value is returned. | |
44 * | |
45 */ | |
46 int subopt_parse( char const * const str, opt_t * opts ) | |
47 { | |
48 int parse_err = 0, idx; | |
49 unsigned int parse_pos = 0; | |
50 | |
51 /* Initialize set member to false. * | |
52 * It is set to true if it was found in str */ | |
53 for ( idx=0; opts[idx].name; ++idx ) | |
54 { | |
55 opts[idx].set = 0; | |
56 } | |
57 | |
58 if ( str ) | |
59 { | |
60 while ( str[parse_pos] && !parse_err ) | |
61 { | |
62 int next = 0; | |
63 | |
64 idx = 0; // reset index for the below loop | |
65 while ( opts[idx].name ) | |
66 { | |
67 int opt_len; | |
68 int substr_len; | |
69 | |
70 // get length of the option we test against */ | |
71 opt_len = strlen( opts[idx].name ); | |
72 | |
73 // get length of the current substring of str */ | |
74 { | |
75 char * delim, * arg_delim; | |
76 | |
77 /* search nearest delimiter ( option or argument delimiter ) */ | |
78 delim = strchr( &str[parse_pos], ':' ); | |
79 arg_delim = strchr( &str[parse_pos], '=' ); | |
80 | |
81 if ( ( delim && arg_delim && delim > arg_delim ) || | |
82 delim == NULL ) | |
83 { | |
84 delim = strchr( &str[parse_pos], '=' ); | |
85 } | |
86 | |
87 substr_len = delim ? // is a delim present | |
88 delim - &str[parse_pos] : // yes | |
89 strlen( &str[parse_pos] ); // no, end of string | |
90 } | |
91 | |
92 //printf( "substr_len=%d, opt_len=%d\n", substr_len, opt_len ); | |
93 | |
94 /* Check if the length of the current option matches the * | |
95 * length of the option we want to test again. */ | |
96 if ( substr_len == opt_len ) | |
97 { | |
98 /* check if option was activated/deactivated */ | |
99 if( strncmp( &str[parse_pos], opts[idx].name, opt_len ) == 0 ) | |
100 { | |
101 /* option was found */ | |
102 opts[idx].set = 1; next = 1; | |
103 | |
104 assert( opts[idx].valp && "Need a pointer to store the arg!" ); | |
105 | |
106 /* type specific code */ | |
107 if ( opts[idx].type == OPT_ARG_BOOL ) | |
108 { | |
109 /* Handle OPT_ARG_BOOL seperately so * | |
110 * the others can share code. */ | |
111 | |
112 /* set option to true */ | |
113 *((int *)(opts[idx].valp)) = 1; | |
114 | |
115 /* increment position */ | |
116 parse_pos += opt_len; | |
117 } | |
118 else | |
119 { | |
120 /* Type is not OPT_ARG_BOOL, means we have to parse * | |
121 * for the arg delimiter character and eventually * | |
122 * call a test function. */ | |
123 char const * last; | |
124 | |
125 /* increment position to check for arg */ | |
126 parse_pos += opt_len; | |
127 | |
128 if ( str[parse_pos] != '=' ) | |
129 { | |
130 parse_err = 1; break; | |
131 } | |
132 | |
133 /* '=' char was there, so let's move after it */ | |
134 ++parse_pos; | |
135 | |
136 switch ( opts[idx].type ) | |
137 { | |
138 case OPT_ARG_INT: | |
139 last = parse_int( &str[parse_pos], | |
140 (int *)opts[idx].valp ); | |
141 | |
142 break; | |
143 case OPT_ARG_STR: | |
144 last = parse_str( &str[parse_pos], | |
145 (strarg_t *)opts[idx].valp ); | |
146 break; | |
147 default: | |
148 assert( 0 && "Arg type of suboption doesn't exist!" ); | |
149 last = NULL; // break parsing! | |
150 } | |
151 | |
152 /* was the conversion succesful? */ | |
153 if ( !last ) | |
154 { | |
155 parse_err = 1; break; | |
156 } | |
157 | |
158 /* make test if supplied */ | |
159 if ( opts[idx].test && !opts[idx].test( opts[idx].valp ) ) | |
160 { | |
161 parse_err = 1; break; | |
162 } | |
163 | |
164 /* we succeded, set position */ | |
165 parse_pos = last - str; | |
166 } | |
167 } | |
168 } | |
169 else if ( substr_len == opt_len+2 ) | |
170 { | |
171 if ( opts[idx].type == OPT_ARG_BOOL && // check for no<opt> | |
172 strncmp( &str[parse_pos], "no", 2 ) == 0 && | |
173 strncmp( &str[parse_pos+2], opts[idx].name, opt_len ) == 0 ) | |
174 { | |
175 /* option was found but negated */ | |
176 opts[idx].set = 1; next = 1; | |
177 | |
178 /* set arg to false */ | |
179 *((int *)(opts[idx].valp)) = 0; | |
180 | |
181 /* increment position */ | |
182 parse_pos += opt_len+2; | |
183 } | |
184 } | |
185 | |
186 ++idx; // test against next option | |
187 | |
188 /* break out of the loop, if this subopt is processed */ | |
189 if ( next ) { break; } | |
190 } | |
191 | |
192 /* if we had a valid suboption the current pos should * | |
193 * equal the delimiter char, which should be ':' for * | |
194 * suboptions. */ | |
195 if ( !parse_err && str[parse_pos] == ':' ) { ++parse_pos; } | |
196 else if ( str[parse_pos] ) { parse_err = 1; } | |
197 } | |
198 } | |
199 | |
200 /* if an error was encountered */ | |
201 if (parse_err) | |
202 { | |
203 unsigned int i; | |
204 mp_msg( MSGT_VO, MSGL_FATAL, "Could not parse arguments at the position indicated below:\n%s\n", str ); | |
205 for ( i = 0; i < parse_pos; ++i ) | |
206 { | |
207 mp_msg(MSGT_VO, MSGL_FATAL, " "); | |
208 } | |
209 mp_msg(MSGT_VO, MSGL_FATAL, "^\n"); | |
210 | |
211 return -1; | |
212 } | |
213 | |
214 /* we could parse everything */ | |
215 return 0; | |
216 } | |
217 | |
218 static char const * parse_int( char const * const str, int * const valp ) | |
219 { | |
220 char * endp; | |
221 | |
222 assert( str && "parse_int(): str == NULL" ); | |
223 | |
224 *valp = (int)strtol( str, &endp, 0 ); | |
225 | |
226 /* nothing was converted */ | |
227 if ( str == endp ) { return NULL; } | |
228 | |
229 return endp; | |
230 } | |
231 | |
232 static char const * parse_str( char const * const str, strarg_t * const valp ) | |
233 { | |
234 char const * match = strchr( str, ':' ); | |
235 | |
236 if ( !match ) | |
14294
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
237 match = &str[strlen(str)]; |
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
238 |
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
239 // empty string or too long |
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
240 if ((match == str) || (match - str > 255)) |
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
241 return NULL; |
14281 | 242 |
243 valp->len = match - str; | |
244 valp->str = str; | |
245 | |
246 return match; | |
247 } |