Mercurial > mplayer.hg
annotate subopt-helper.c @ 29409:4b0a12d0e5bd
Indent.
author | ramiro |
---|---|
date | Tue, 28 Jul 2009 05:14:47 +0000 |
parents | 3b9429f763e2 |
children | 1772a5171ac7 |
rev | line source |
---|---|
29252 | 1 /** |
14281 | 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> | |
14538
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
25 #include <limits.h> |
14281 | 26 #include <assert.h> |
27 | |
28 #ifndef MPDEBUG | |
29 #define NDEBUG | |
30 #endif | |
31 | |
32 /* prototypes for argument parsing */ | |
33 static char const * parse_int( char const * const str, int * const valp ); | |
34 static char const * parse_str( char const * const str, strarg_t * const valp ); | |
16720 | 35 static char const * parse_float( char const * const str, float * const valp ); |
14281 | 36 |
37 /** | |
38 * \brief Try to parse all options in str and fail if it was not possible. | |
39 * | |
40 * \param str Pointer to the zero terminated string to be parsed. | |
41 * \param opts Pointer to a options array. The array must be terminated | |
42 * with an element having set name to NULL in its opt_t structure. | |
43 * | |
44 * \return The return value is zero if the string could be parsed | |
45 * else a non-zero value is returned. | |
46 * | |
47 */ | |
28827
2b021e3e1000
Get rid of the "set" member of the subopt-parser struct, it made
reimar
parents:
22283
diff
changeset
|
48 int subopt_parse( char const * const str, const opt_t * opts ) |
14281 | 49 { |
50 int parse_err = 0, idx; | |
51 unsigned int parse_pos = 0; | |
52 | |
53 if ( str ) | |
54 { | |
55 while ( str[parse_pos] && !parse_err ) | |
56 { | |
57 int next = 0; | |
58 | |
59 idx = 0; // reset index for the below loop | |
60 while ( opts[idx].name ) | |
61 { | |
62 int opt_len; | |
63 int substr_len; | |
64 | |
65 // get length of the option we test against */ | |
66 opt_len = strlen( opts[idx].name ); | |
67 | |
68 // get length of the current substring of str */ | |
69 { | |
70 char * delim, * arg_delim; | |
71 | |
29252 | 72 /* search nearest delimiter ( option or argument delimiter ) */ |
14281 | 73 delim = strchr( &str[parse_pos], ':' ); |
74 arg_delim = strchr( &str[parse_pos], '=' ); | |
75 | |
76 if ( ( delim && arg_delim && delim > arg_delim ) || | |
77 delim == NULL ) | |
78 { | |
79 delim = strchr( &str[parse_pos], '=' ); | |
80 } | |
29252 | 81 |
14281 | 82 substr_len = delim ? // is a delim present |
83 delim - &str[parse_pos] : // yes | |
84 strlen( &str[parse_pos] ); // no, end of string | |
85 } | |
86 | |
87 //printf( "substr_len=%d, opt_len=%d\n", substr_len, opt_len ); | |
88 | |
89 /* Check if the length of the current option matches the * | |
90 * length of the option we want to test again. */ | |
91 if ( substr_len == opt_len ) | |
92 { | |
93 /* check if option was activated/deactivated */ | |
94 if( strncmp( &str[parse_pos], opts[idx].name, opt_len ) == 0 ) | |
95 { | |
96 /* option was found */ | |
28827
2b021e3e1000
Get rid of the "set" member of the subopt-parser struct, it made
reimar
parents:
22283
diff
changeset
|
97 next = 1; |
14281 | 98 |
99 assert( opts[idx].valp && "Need a pointer to store the arg!" ); | |
100 | |
101 /* type specific code */ | |
102 if ( opts[idx].type == OPT_ARG_BOOL ) | |
103 { | |
22283
bc9e95184521
cosmetics: Fix some common typos, sepErate --> sepArate, deciSSion --> deciSion.
diego
parents:
19104
diff
changeset
|
104 /* Handle OPT_ARG_BOOL separately so * |
14281 | 105 * the others can share code. */ |
106 | |
107 /* set option to true */ | |
108 *((int *)(opts[idx].valp)) = 1; | |
109 | |
110 /* increment position */ | |
111 parse_pos += opt_len; | |
112 } | |
113 else | |
114 { | |
115 /* Type is not OPT_ARG_BOOL, means we have to parse * | |
116 * for the arg delimiter character and eventually * | |
117 * call a test function. */ | |
118 char const * last; | |
119 | |
120 /* increment position to check for arg */ | |
121 parse_pos += opt_len; | |
122 | |
123 if ( str[parse_pos] != '=' ) | |
124 { | |
125 parse_err = 1; break; | |
126 } | |
127 | |
128 /* '=' char was there, so let's move after it */ | |
129 ++parse_pos; | |
130 | |
131 switch ( opts[idx].type ) | |
132 { | |
133 case OPT_ARG_INT: | |
134 last = parse_int( &str[parse_pos], | |
135 (int *)opts[idx].valp ); | |
136 | |
137 break; | |
138 case OPT_ARG_STR: | |
139 last = parse_str( &str[parse_pos], | |
140 (strarg_t *)opts[idx].valp ); | |
141 break; | |
14538
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
142 case OPT_ARG_MSTRZ: |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
143 { |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
144 char **valp = opts[idx].valp; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
145 strarg_t tmp; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
146 tmp.str = NULL; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
147 tmp.len = 0; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
148 last = parse_str( &str[parse_pos], &tmp ); |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
149 if (*valp) |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
150 free(*valp); |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
151 *valp = NULL; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
152 if (tmp.str && tmp.len > 0) { |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
153 *valp = malloc(tmp.len + 1); |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
154 memcpy(*valp, tmp.str, tmp.len); |
14572 | 155 (*valp)[tmp.len] = 0; |
14538
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
156 } |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
157 break; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
158 } |
16720 | 159 case OPT_ARG_FLOAT: |
160 last = parse_float( &str[parse_pos], | |
161 (float *)opts[idx].valp ); | |
162 break; | |
14281 | 163 default: |
164 assert( 0 && "Arg type of suboption doesn't exist!" ); | |
165 last = NULL; // break parsing! | |
166 } | |
167 | |
168 /* was the conversion succesful? */ | |
169 if ( !last ) | |
170 { | |
171 parse_err = 1; break; | |
172 } | |
173 | |
174 /* make test if supplied */ | |
175 if ( opts[idx].test && !opts[idx].test( opts[idx].valp ) ) | |
176 { | |
177 parse_err = 1; break; | |
178 } | |
179 | |
180 /* we succeded, set position */ | |
181 parse_pos = last - str; | |
182 } | |
183 } | |
184 } | |
185 else if ( substr_len == opt_len+2 ) | |
186 { | |
187 if ( opts[idx].type == OPT_ARG_BOOL && // check for no<opt> | |
188 strncmp( &str[parse_pos], "no", 2 ) == 0 && | |
189 strncmp( &str[parse_pos+2], opts[idx].name, opt_len ) == 0 ) | |
190 { | |
191 /* option was found but negated */ | |
28827
2b021e3e1000
Get rid of the "set" member of the subopt-parser struct, it made
reimar
parents:
22283
diff
changeset
|
192 next = 1; |
14281 | 193 |
194 /* set arg to false */ | |
195 *((int *)(opts[idx].valp)) = 0; | |
196 | |
197 /* increment position */ | |
198 parse_pos += opt_len+2; | |
199 } | |
200 } | |
201 | |
202 ++idx; // test against next option | |
203 | |
204 /* break out of the loop, if this subopt is processed */ | |
205 if ( next ) { break; } | |
206 } | |
29252 | 207 |
14281 | 208 /* if we had a valid suboption the current pos should * |
209 * equal the delimiter char, which should be ':' for * | |
210 * suboptions. */ | |
211 if ( !parse_err && str[parse_pos] == ':' ) { ++parse_pos; } | |
212 else if ( str[parse_pos] ) { parse_err = 1; } | |
213 } | |
214 } | |
215 | |
216 /* if an error was encountered */ | |
217 if (parse_err) | |
218 { | |
219 unsigned int i; | |
220 mp_msg( MSGT_VO, MSGL_FATAL, "Could not parse arguments at the position indicated below:\n%s\n", str ); | |
221 for ( i = 0; i < parse_pos; ++i ) | |
222 { | |
223 mp_msg(MSGT_VO, MSGL_FATAL, " "); | |
224 } | |
225 mp_msg(MSGT_VO, MSGL_FATAL, "^\n"); | |
226 | |
227 return -1; | |
228 } | |
229 | |
230 /* we could parse everything */ | |
231 return 0; | |
232 } | |
233 | |
234 static char const * parse_int( char const * const str, int * const valp ) | |
235 { | |
236 char * endp; | |
237 | |
238 assert( str && "parse_int(): str == NULL" ); | |
239 | |
240 *valp = (int)strtol( str, &endp, 0 ); | |
241 | |
242 /* nothing was converted */ | |
243 if ( str == endp ) { return NULL; } | |
244 | |
245 return endp; | |
246 } | |
247 | |
16720 | 248 static char const * parse_float( char const * const str, float * const valp ) |
249 { | |
250 char * endp; | |
251 | |
252 assert( str && "parse_float(): str == NULL" ); | |
253 | |
16725
2a7220c457a7
1l, strtof is only C99, strtod is ANSI C, so use that instead.
reimar
parents:
16720
diff
changeset
|
254 *valp = strtod( str, &endp ); |
16720 | 255 |
256 /* nothing was converted */ | |
257 if ( str == endp ) { return NULL; } | |
258 | |
259 return endp; | |
260 } | |
261 | |
15733
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
262 #define QUOTE_CHAR '%' |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
263 static char const * parse_str( char const * str, strarg_t * const valp ) |
14281 | 264 { |
265 char const * match = strchr( str, ':' ); | |
266 | |
15733
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
267 if (str[0] == QUOTE_CHAR) { |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
268 int len = 0; |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
269 str = &str[1]; |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
270 len = (int)strtol(str, (char **)&str, 0); |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
271 if (!str || str[0] != QUOTE_CHAR || (len > strlen(str) - 1)) |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
272 return NULL; |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
273 str = &str[1]; |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
274 match = &str[len]; |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
275 } |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
276 else |
16609 | 277 if (str[0] == '"') { |
278 str = &str[1]; | |
279 match = strchr(str, '"'); | |
280 if (!match) | |
281 return NULL; | |
282 valp->len = match - str; | |
283 valp->str = str; | |
284 return &match[1]; | |
285 } | |
14281 | 286 if ( !match ) |
14294
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
287 match = &str[strlen(str)]; |
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
288 |
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
289 // empty string or too long |
14538
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
290 if ((match == str) || (match - str > INT_MAX)) |
14294
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
291 return NULL; |
14281 | 292 |
293 valp->len = match - str; | |
294 valp->str = str; | |
295 | |
296 return match; | |
297 } | |
14736 | 298 |
299 | |
300 /*** common test functions ***/ | |
301 | |
302 /** \brief Test if i is not negative */ | |
303 int int_non_neg( int * i ) | |
304 { | |
305 if ( *i < 0 ) { return 0; } | |
306 | |
307 return 1; | |
308 } | |
309 /** \brief Test if i is positive. */ | |
310 int int_pos( int * i ) | |
311 { | |
312 if ( *i > 0 ) { return 1; } | |
313 | |
314 return 0; | |
315 } | |
15734
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
316 |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
317 /*** little helpers */ |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
318 |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
319 /** \brief compare the stings just as strcmp does */ |
19104
2ec2301183cd
marks several read-only string parameters which aren't modified inside the called function as const. Patch by Stefan Huehner, stefan AT huehner-org
reynaldo
parents:
16725
diff
changeset
|
320 int strargcmp(strarg_t *arg, const char *str) { |
15734
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
321 int res = strncmp(arg->str, str, arg->len); |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
322 if (!res && arg->len != strlen(str)) |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
323 res = arg->len - strlen(str); |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
324 return res; |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
325 } |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
326 |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
327 /** \brief compare the stings just as strcasecmp does */ |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
328 int strargcasecmp(strarg_t *arg, char *str) { |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
329 int res = strncasecmp(arg->str, str, arg->len); |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
330 if (!res && arg->len != strlen(str)) |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
331 res = arg->len - strlen(str); |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
332 return res; |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
333 } |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
334 |