Mercurial > mplayer.hg
annotate subopt-helper.c @ 29221:84ed872376f3
Add #define for HAVE_DVDCSS_DVDCSS_H (needed by internal libdvdread) to config.h
instead of passing -D on the compiler command line.
This is more convenient and already done with most preprocessor definitions
needed by external libraries.
Previously the definition was passed on the command line because libdvdread was
missing the necessary config.h #include, which was now added.
author | diego |
---|---|
date | Tue, 05 May 2009 17:30:50 +0000 |
parents | 2b021e3e1000 |
children | 3b9429f763e2 |
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 */ | |
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 | |
72 /* search nearest delimiter ( option or argument delimiter ) */ | |
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 } | |
81 | |
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 } | |
207 | |
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 |