Mercurial > mplayer.hg
annotate subopt-helper.c @ 19619:a83e5b8d2e63
Patch from Karolina Lindqvist <karolina.lindqvist@kramnet.se>
"There is a bug in the zoran -vo zr driver, that makes the output garbled
always. It also probably affects the zrmjpeg filter. This patch takes care of
the problem."
Patch tested and OK. And 10l to me, because this bug probably has existed for a
looong time.
author | rik |
---|---|
date | Fri, 01 Sep 2006 18:49:40 +0000 |
parents | 2ec2301183cd |
children | bc9e95184521 |
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> | |
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 */ | |
48 int subopt_parse( char const * const str, opt_t * opts ) | |
49 { | |
50 int parse_err = 0, idx; | |
51 unsigned int parse_pos = 0; | |
52 | |
53 /* Initialize set member to false. * | |
54 * It is set to true if it was found in str */ | |
55 for ( idx=0; opts[idx].name; ++idx ) | |
56 { | |
57 opts[idx].set = 0; | |
58 } | |
59 | |
60 if ( str ) | |
61 { | |
62 while ( str[parse_pos] && !parse_err ) | |
63 { | |
64 int next = 0; | |
65 | |
66 idx = 0; // reset index for the below loop | |
67 while ( opts[idx].name ) | |
68 { | |
69 int opt_len; | |
70 int substr_len; | |
71 | |
72 // get length of the option we test against */ | |
73 opt_len = strlen( opts[idx].name ); | |
74 | |
75 // get length of the current substring of str */ | |
76 { | |
77 char * delim, * arg_delim; | |
78 | |
79 /* search nearest delimiter ( option or argument delimiter ) */ | |
80 delim = strchr( &str[parse_pos], ':' ); | |
81 arg_delim = strchr( &str[parse_pos], '=' ); | |
82 | |
83 if ( ( delim && arg_delim && delim > arg_delim ) || | |
84 delim == NULL ) | |
85 { | |
86 delim = strchr( &str[parse_pos], '=' ); | |
87 } | |
88 | |
89 substr_len = delim ? // is a delim present | |
90 delim - &str[parse_pos] : // yes | |
91 strlen( &str[parse_pos] ); // no, end of string | |
92 } | |
93 | |
94 //printf( "substr_len=%d, opt_len=%d\n", substr_len, opt_len ); | |
95 | |
96 /* Check if the length of the current option matches the * | |
97 * length of the option we want to test again. */ | |
98 if ( substr_len == opt_len ) | |
99 { | |
100 /* check if option was activated/deactivated */ | |
101 if( strncmp( &str[parse_pos], opts[idx].name, opt_len ) == 0 ) | |
102 { | |
103 /* option was found */ | |
104 opts[idx].set = 1; next = 1; | |
105 | |
106 assert( opts[idx].valp && "Need a pointer to store the arg!" ); | |
107 | |
108 /* type specific code */ | |
109 if ( opts[idx].type == OPT_ARG_BOOL ) | |
110 { | |
111 /* Handle OPT_ARG_BOOL seperately so * | |
112 * the others can share code. */ | |
113 | |
114 /* set option to true */ | |
115 *((int *)(opts[idx].valp)) = 1; | |
116 | |
117 /* increment position */ | |
118 parse_pos += opt_len; | |
119 } | |
120 else | |
121 { | |
122 /* Type is not OPT_ARG_BOOL, means we have to parse * | |
123 * for the arg delimiter character and eventually * | |
124 * call a test function. */ | |
125 char const * last; | |
126 | |
127 /* increment position to check for arg */ | |
128 parse_pos += opt_len; | |
129 | |
130 if ( str[parse_pos] != '=' ) | |
131 { | |
132 parse_err = 1; break; | |
133 } | |
134 | |
135 /* '=' char was there, so let's move after it */ | |
136 ++parse_pos; | |
137 | |
138 switch ( opts[idx].type ) | |
139 { | |
140 case OPT_ARG_INT: | |
141 last = parse_int( &str[parse_pos], | |
142 (int *)opts[idx].valp ); | |
143 | |
144 break; | |
145 case OPT_ARG_STR: | |
146 last = parse_str( &str[parse_pos], | |
147 (strarg_t *)opts[idx].valp ); | |
148 break; | |
14538
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
149 case OPT_ARG_MSTRZ: |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
150 { |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
151 char **valp = opts[idx].valp; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
152 strarg_t tmp; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
153 tmp.str = NULL; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
154 tmp.len = 0; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
155 last = parse_str( &str[parse_pos], &tmp ); |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
156 if (*valp) |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
157 free(*valp); |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
158 *valp = NULL; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
159 if (tmp.str && tmp.len > 0) { |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
160 *valp = malloc(tmp.len + 1); |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
161 memcpy(*valp, tmp.str, tmp.len); |
14572 | 162 (*valp)[tmp.len] = 0; |
14538
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
163 } |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
164 break; |
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
165 } |
16720 | 166 case OPT_ARG_FLOAT: |
167 last = parse_float( &str[parse_pos], | |
168 (float *)opts[idx].valp ); | |
169 break; | |
14281 | 170 default: |
171 assert( 0 && "Arg type of suboption doesn't exist!" ); | |
172 last = NULL; // break parsing! | |
173 } | |
174 | |
175 /* was the conversion succesful? */ | |
176 if ( !last ) | |
177 { | |
178 parse_err = 1; break; | |
179 } | |
180 | |
181 /* make test if supplied */ | |
182 if ( opts[idx].test && !opts[idx].test( opts[idx].valp ) ) | |
183 { | |
184 parse_err = 1; break; | |
185 } | |
186 | |
187 /* we succeded, set position */ | |
188 parse_pos = last - str; | |
189 } | |
190 } | |
191 } | |
192 else if ( substr_len == opt_len+2 ) | |
193 { | |
194 if ( opts[idx].type == OPT_ARG_BOOL && // check for no<opt> | |
195 strncmp( &str[parse_pos], "no", 2 ) == 0 && | |
196 strncmp( &str[parse_pos+2], opts[idx].name, opt_len ) == 0 ) | |
197 { | |
198 /* option was found but negated */ | |
199 opts[idx].set = 1; next = 1; | |
200 | |
201 /* set arg to false */ | |
202 *((int *)(opts[idx].valp)) = 0; | |
203 | |
204 /* increment position */ | |
205 parse_pos += opt_len+2; | |
206 } | |
207 } | |
208 | |
209 ++idx; // test against next option | |
210 | |
211 /* break out of the loop, if this subopt is processed */ | |
212 if ( next ) { break; } | |
213 } | |
214 | |
215 /* if we had a valid suboption the current pos should * | |
216 * equal the delimiter char, which should be ':' for * | |
217 * suboptions. */ | |
218 if ( !parse_err && str[parse_pos] == ':' ) { ++parse_pos; } | |
219 else if ( str[parse_pos] ) { parse_err = 1; } | |
220 } | |
221 } | |
222 | |
223 /* if an error was encountered */ | |
224 if (parse_err) | |
225 { | |
226 unsigned int i; | |
227 mp_msg( MSGT_VO, MSGL_FATAL, "Could not parse arguments at the position indicated below:\n%s\n", str ); | |
228 for ( i = 0; i < parse_pos; ++i ) | |
229 { | |
230 mp_msg(MSGT_VO, MSGL_FATAL, " "); | |
231 } | |
232 mp_msg(MSGT_VO, MSGL_FATAL, "^\n"); | |
233 | |
234 return -1; | |
235 } | |
236 | |
237 /* we could parse everything */ | |
238 return 0; | |
239 } | |
240 | |
241 static char const * parse_int( char const * const str, int * const valp ) | |
242 { | |
243 char * endp; | |
244 | |
245 assert( str && "parse_int(): str == NULL" ); | |
246 | |
247 *valp = (int)strtol( str, &endp, 0 ); | |
248 | |
249 /* nothing was converted */ | |
250 if ( str == endp ) { return NULL; } | |
251 | |
252 return endp; | |
253 } | |
254 | |
16720 | 255 static char const * parse_float( char const * const str, float * const valp ) |
256 { | |
257 char * endp; | |
258 | |
259 assert( str && "parse_float(): str == NULL" ); | |
260 | |
16725
2a7220c457a7
1l, strtof is only C99, strtod is ANSI C, so use that instead.
reimar
parents:
16720
diff
changeset
|
261 *valp = strtod( str, &endp ); |
16720 | 262 |
263 /* nothing was converted */ | |
264 if ( str == endp ) { return NULL; } | |
265 | |
266 return endp; | |
267 } | |
268 | |
15733
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
269 #define QUOTE_CHAR '%' |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
270 static char const * parse_str( char const * str, strarg_t * const valp ) |
14281 | 271 { |
272 char const * match = strchr( str, ':' ); | |
273 | |
15733
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
274 if (str[0] == QUOTE_CHAR) { |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
275 int len = 0; |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
276 str = &str[1]; |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
277 len = (int)strtol(str, (char **)&str, 0); |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
278 if (!str || str[0] != QUOTE_CHAR || (len > strlen(str) - 1)) |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
279 return NULL; |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
280 str = &str[1]; |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
281 match = &str[len]; |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
282 } |
e678e306068e
support lenght-quoting of strings in subopt parser.
reimar
parents:
14736
diff
changeset
|
283 else |
16609 | 284 if (str[0] == '"') { |
285 str = &str[1]; | |
286 match = strchr(str, '"'); | |
287 if (!match) | |
288 return NULL; | |
289 valp->len = match - str; | |
290 valp->str = str; | |
291 return &match[1]; | |
292 } | |
14281 | 293 if ( !match ) |
14294
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
294 match = &str[strlen(str)]; |
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
295 |
90bcd37dba7f
fix string argument parsing (e.g. one char strings were not accepted)
reimar
parents:
14281
diff
changeset
|
296 // empty string or too long |
14538
00c3c4111017
New suboption type: malloc'ed, zero terminated string
reimar
parents:
14294
diff
changeset
|
297 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
|
298 return NULL; |
14281 | 299 |
300 valp->len = match - str; | |
301 valp->str = str; | |
302 | |
303 return match; | |
304 } | |
14736 | 305 |
306 | |
307 /*** common test functions ***/ | |
308 | |
309 /** \brief Test if i is not negative */ | |
310 int int_non_neg( int * i ) | |
311 { | |
312 if ( *i < 0 ) { return 0; } | |
313 | |
314 return 1; | |
315 } | |
316 /** \brief Test if i is positive. */ | |
317 int int_pos( int * i ) | |
318 { | |
319 if ( *i > 0 ) { return 1; } | |
320 | |
321 return 0; | |
322 } | |
15734
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
323 |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
324 /*** little helpers */ |
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 /** \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
|
327 int strargcmp(strarg_t *arg, const char *str) { |
15734
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
328 int res = strncmp(arg->str, str, arg->len); |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
329 if (!res && arg->len != strlen(str)) |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
330 res = arg->len - strlen(str); |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
331 return res; |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
332 } |
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 /** \brief compare the stings just as strcasecmp does */ |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
335 int strargcasecmp(strarg_t *arg, char *str) { |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
336 int res = strncasecmp(arg->str, str, arg->len); |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
337 if (!res && arg->len != strlen(str)) |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
338 res = arg->len - strlen(str); |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
339 return res; |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
340 } |
7e4fa8fc255c
helper functions for comparing strarg_t "strings".
reimar
parents:
15733
diff
changeset
|
341 |