demux_ts: fix crash on broken packets
[mplayer/glamo.git] / subopt-helper.c
blob31cedeef6ce2db214b8685ea92f23db44fd0b5c5
1 /*
2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 /**
20 * \file subopt-helper.c
22 * \brief Compensates the suboption parsing code duplication a bit.
24 * The routines defined below are there to help you with the
25 * suboption parsing. Meaning extracting the options and their
26 * values for you and also outputting generic help message if
27 * a parse error is encountered.
29 * Most stuff happens in the subopt_parse function: if you call it
30 * it parses for the passed opts in the passed string. It calls some
31 * extra functions for explicit argument parsing ( where the option
32 * itself isn't the argument but a value given after the argument
33 * delimiter ('='). It also calls your test function if you supplied
34 * one.
38 #include "subopt-helper.h"
39 #include "mp_msg.h"
41 #include <stdlib.h>
42 #include <string.h>
43 #include <limits.h>
44 #include <assert.h>
46 #ifndef MPDEBUG
47 #define NDEBUG
48 #endif
50 /* prototypes for argument parsing */
51 static char const * parse_int( char const * const str, int * const valp );
52 static char const * parse_str( char const * const str, strarg_t * const valp );
53 static char const * parse_float( char const * const str, float * const valp );
55 /**
56 * \brief Try to parse all options in str and fail if it was not possible.
58 * \param str Pointer to the zero terminated string to be parsed.
59 * \param opts Pointer to a options array. The array must be terminated
60 * with an element having set name to NULL in its opt_t structure.
62 * \return The return value is zero if the string could be parsed
63 * else a non-zero value is returned.
66 int subopt_parse( char const * const str, const opt_t * opts )
68 int parse_err = 0, idx;
69 unsigned int parse_pos = 0;
71 if ( str )
73 while ( str[parse_pos] && !parse_err )
75 int next = 0;
77 idx = 0; // reset index for the below loop
78 while ( opts[idx].name )
80 int opt_len;
81 int substr_len;
83 // get length of the option we test against */
84 opt_len = strlen( opts[idx].name );
86 // get length of the current substring of str */
88 char * delim, * arg_delim;
90 /* search nearest delimiter ( option or argument delimiter ) */
91 delim = strchr( &str[parse_pos], ':' );
92 arg_delim = strchr( &str[parse_pos], '=' );
94 if ( ( delim && arg_delim && delim > arg_delim ) ||
95 delim == NULL )
97 delim = strchr( &str[parse_pos], '=' );
100 substr_len = delim ? // is a delim present
101 delim - &str[parse_pos] : // yes
102 strlen( &str[parse_pos] ); // no, end of string
105 //printf( "substr_len=%d, opt_len=%d\n", substr_len, opt_len );
107 /* Check if the length of the current option matches the *
108 * length of the option we want to test again. */
109 if ( substr_len == opt_len )
111 /* check if option was activated/deactivated */
112 if( strncmp( &str[parse_pos], opts[idx].name, opt_len ) == 0 )
114 /* option was found */
115 next = 1;
117 assert( opts[idx].valp && "Need a pointer to store the arg!" );
119 /* type specific code */
120 if ( opts[idx].type == OPT_ARG_BOOL )
122 /* Handle OPT_ARG_BOOL separately so *
123 * the others can share code. */
125 /* set option to true */
126 *((int *)(opts[idx].valp)) = 1;
128 /* increment position */
129 parse_pos += opt_len;
131 else
133 /* Type is not OPT_ARG_BOOL, means we have to parse *
134 * for the arg delimiter character and eventually *
135 * call a test function. */
136 char const * last;
138 /* increment position to check for arg */
139 parse_pos += opt_len;
141 if ( str[parse_pos] != '=' )
143 parse_err = 1; break;
146 /* '=' char was there, so let's move after it */
147 ++parse_pos;
149 switch ( opts[idx].type )
151 case OPT_ARG_INT:
152 last = parse_int( &str[parse_pos],
153 (int *)opts[idx].valp );
155 break;
156 case OPT_ARG_STR:
157 last = parse_str( &str[parse_pos],
158 (strarg_t *)opts[idx].valp );
159 break;
160 case OPT_ARG_MSTRZ:
162 char **valp = opts[idx].valp;
163 strarg_t tmp;
164 tmp.str = NULL;
165 tmp.len = 0;
166 last = parse_str( &str[parse_pos], &tmp );
167 if (*valp)
168 free(*valp);
169 *valp = NULL;
170 if (tmp.str && tmp.len > 0) {
171 *valp = malloc(tmp.len + 1);
172 memcpy(*valp, tmp.str, tmp.len);
173 (*valp)[tmp.len] = 0;
175 break;
177 case OPT_ARG_FLOAT:
178 last = parse_float( &str[parse_pos],
179 (float *)opts[idx].valp );
180 break;
181 default:
182 assert( 0 && "Arg type of suboption doesn't exist!" );
183 last = NULL; // break parsing!
186 /* was the conversion succesful? */
187 if ( !last )
189 parse_err = 1; break;
192 /* make test if supplied */
193 if ( opts[idx].test && !opts[idx].test( opts[idx].valp ) )
195 parse_err = 1; break;
198 /* we succeded, set position */
199 parse_pos = last - str;
203 else if ( substr_len == opt_len+2 )
205 if ( opts[idx].type == OPT_ARG_BOOL && // check for no<opt>
206 strncmp( &str[parse_pos], "no", 2 ) == 0 &&
207 strncmp( &str[parse_pos+2], opts[idx].name, opt_len ) == 0 )
209 /* option was found but negated */
210 next = 1;
212 /* set arg to false */
213 *((int *)(opts[idx].valp)) = 0;
215 /* increment position */
216 parse_pos += opt_len+2;
220 ++idx; // test against next option
222 /* break out of the loop, if this subopt is processed */
223 if ( next ) { break; }
226 /* if we had a valid suboption the current pos should *
227 * equal the delimiter char, which should be ':' for *
228 * suboptions. */
229 if ( !parse_err && str[parse_pos] == ':' ) { ++parse_pos; }
230 else if ( str[parse_pos] ) { parse_err = 1; }
234 /* if an error was encountered */
235 if (parse_err)
237 unsigned int i;
238 mp_msg( MSGT_VO, MSGL_FATAL, "Could not parse arguments at the position indicated below:\n%s\n", str );
239 for ( i = 0; i < parse_pos; ++i )
241 mp_msg(MSGT_VO, MSGL_FATAL, " ");
243 mp_msg(MSGT_VO, MSGL_FATAL, "^\n");
245 return -1;
248 /* we could parse everything */
249 return 0;
252 static char const * parse_int( char const * const str, int * const valp )
254 char * endp;
256 assert( str && "parse_int(): str == NULL" );
258 *valp = (int)strtol( str, &endp, 0 );
260 /* nothing was converted */
261 if ( str == endp ) { return NULL; }
263 return endp;
266 static char const * parse_float( char const * const str, float * const valp )
268 char * endp;
270 assert( str && "parse_float(): str == NULL" );
272 *valp = strtod( str, &endp );
274 /* nothing was converted */
275 if ( str == endp ) { return NULL; }
277 return endp;
280 #define QUOTE_CHAR '%'
281 static char const * parse_str( char const * str, strarg_t * const valp )
283 char const * match = strchr( str, ':' );
285 if (str[0] == QUOTE_CHAR) {
286 int len = 0;
287 str = &str[1];
288 len = (int)strtol(str, (char **)&str, 0);
289 if (!str || str[0] != QUOTE_CHAR || (len > strlen(str) - 1))
290 return NULL;
291 str = &str[1];
292 match = &str[len];
294 else
295 if (str[0] == '"') {
296 str = &str[1];
297 match = strchr(str, '"');
298 if (!match)
299 return NULL;
300 valp->len = match - str;
301 valp->str = str;
302 return &match[1];
304 if ( !match )
305 match = &str[strlen(str)];
307 // empty string or too long
308 if ((match == str) || (match - str > INT_MAX))
309 return NULL;
311 valp->len = match - str;
312 valp->str = str;
314 return match;
318 /*** common test functions ***/
320 /** \brief Test if i is not negative */
321 int int_non_neg(void *iptr)
323 int *i = iptr;
324 return *i >= 0;
326 /** \brief Test if i is positive. */
327 int int_pos(void *iptr)
329 int *i = iptr;
330 return *i > 0;
333 /*** little helpers */
335 /** \brief compare the stings just as strcmp does */
336 int strargcmp(strarg_t *arg, const char *str) {
337 int res = strncmp(arg->str, str, arg->len);
338 if (!res && arg->len != strlen(str))
339 res = arg->len - strlen(str);
340 return res;
343 /** \brief compare the stings just as strcasecmp does */
344 int strargcasecmp(strarg_t *arg, char *str) {
345 int res = strncasecmp(arg->str, str, arg->len);
346 if (!res && arg->len != strlen(str))
347 res = arg->len - strlen(str);
348 return res;