3 * sushivision copyright (C) 2006-2007 Monty <monty@xiph.org>
5 * sushivision is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * sushivision is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with sushivision; see the file COPYING. If not, write to the
17 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* you should never write your own parser. ever. */
32 // not a true recursive parser as there's no arbitrary nesting.
34 void _sv_tokenval_free(_sv_tokenval
*v
){
41 void _sv_token_free(_sv_token
*t
){
43 if(t
->name
)free(t
->name
);
44 if(t
->label
)free(t
->label
);
48 if(t
->values
[i
])_sv_tokenval_free(t
->values
[i
]);
56 void _sv_tokenlist_free(_sv_tokenlist
*l
){
61 if(l
->list
[i
])_sv_token_free(l
->list
[i
]);
68 // don't allow locale conventions to screw up built-in number strings.
69 // Sorry, but we're hardcoding decimal points in the float syntax. This is
70 // for built-in arg strings, we can substitute in labels later if
72 static float atof_portable(char *number
){
84 while(number
&& *number
&& isspace(*number
))number
++;
87 if(number
&& *number
=='-'){
91 if(number
&& *number
=='+'){
96 while(number
&& *number
>='0' && *number
<='9'){
97 d
= d
*10+(*number
-48);
103 if(number
&& *number
=='.'){
108 while(number
&& *number
>='0' && *number
<='9'){
109 f
= f
*10+(*number
-48);
115 // exponent seperator
116 if(number
&& (*number
=='e' || *number
=='E')){
120 if(number
&& *number
=='-'){
124 if(number
&& *number
=='+'){
127 while(number
&& *number
>='0' && *number
<='9'){
128 e
= e
*10+(*number
-48);
132 if(*number
)return NAN
;
133 if(!eflag
)return NAN
;
136 if(!dflag
&& !fflag
)return NAN
;
137 return msign
*(d
+f
*powf(10,fe
))*powf(10,e
*esign
);
140 static char *trim(char *in
){
145 while(*head
&& isspace(*head
))head
++;
151 while(tail
>in
&& isspace(*(tail
-1)))tail
--;
157 static char *unescape(char *a
){
167 if(*head
!='\\' || escape
){
181 char *_sv_tokenize_escape(char *a
){
187 while(head
&& *head
){
200 ret
=tail
=calloc(count
+1,sizeof(*tail
));
202 while(head
&& *head
){
220 // split at unescaped, unenclosed seperator
221 // only parens enclose in our syntax
222 static char *split(char *a
, char sep
){
229 if(*arg
=='(' && !escape
){
232 if(*arg
==')' && !escape
){
235 fprintf(stderr
,"sushivision: ignoring extraneous paren in \"%s\".\n",
241 if(*arg
==sep
&& !escape
&& level
==0){
242 // we've found our split point
258 static int splitcount(char *a
, char sep
){
265 if(*arg
=='(' && !escape
){
268 if(*arg
==')' && !escape
){
272 if(*arg
==sep
&& !escape
&& level
==0)
287 // unwrap contents enclosed by first level of parens
288 // only parens enclose in our syntax
289 static char *unwrap(char *a
){
296 if(*arg
=='(' && !escape
){
303 if(*arg
==')' && !escape
){
310 fprintf(stderr
,"sushivision: ignoring extraneous paren in \"%s\".\n",
325 fprintf(stderr
,"sushivision: unbalanced paren(s) at \"%s(%s\".\n",
332 // a string is any C string of characters not containing unescaped
333 // parens, commas, colons. Preceeding and trailing spaces are
334 // stripped (escaped spaces are never stripped). Thus, parsing a
335 // string consists only of stripping spaces and checking for illegal
337 char *_sv_tokenize_string(char *in
){
339 char *a
= strdup(in
);
342 // ignore anything following a comma
344 fprintf(stderr
,"sushivision: ignoring trailing garbage \"%s\".\n",a
);
346 // ignore anything following a colon
348 fprintf(stderr
,"sushivision: ignoring trailing garbage after \"%s\".\n",a
);
350 // complain about unescaped parens
352 fprintf(stderr
,"sushivision: ignoring garbage after \"%s\".\n",a
);
354 if(*a
=='\0')goto done
;
356 ret
= strdup(trim(unescape(a
)));
363 // a number is a standard printf format floating point number string
364 // representation. It may not contain any characters (aside from
365 // trailing/preceeding spaces) that are not part of the number
367 _sv_tokenval
*_sv_tokenize_number(char *in
){
369 char *a
= strdup(in
);
370 _sv_tokenval
*ret
=NULL
;
372 a
= trim(unescape(a
));
373 if(*a
=='\0')goto done
;
375 ret
=calloc(1,sizeof(*ret
));
377 ret
->v
= atof_portable(a
);
385 _sv_token
*_sv_tokenize_name(char *in
){
386 _sv_token
*ret
= NULL
;
387 char *s
= _sv_tokenize_string(in
);
390 ret
=calloc(1,sizeof(*ret
));
395 _sv_token
*_sv_tokenize_labelname(char *in
){
397 char *a
= strdup(in
);
398 _sv_token
*ret
= NULL
;
401 char *l
=split(a
,':');
402 ret
= _sv_tokenize_name(a
);
406 ret
->label
= strdup(ret
->name
);
408 char *label
= _sv_tokenize_string(l
);
410 ret
->label
= strdup("");
420 _sv_tokenval
*_sv_tokenize_displayvalue(char *in
){
422 char *a
= strdup(in
);
423 _sv_tokenval
*ret
= NULL
;
426 char *l
=split(a
,':');
427 ret
= _sv_tokenize_number(a
);
431 char *label
= _sv_tokenize_string(l
);
432 if(ret
->s
) free(ret
->s
);
444 _sv_tokenval
*_sv_tokenize_flag(char *in
){
445 _sv_tokenval
*ret
= NULL
;
446 char *s
= _sv_tokenize_string(in
);
449 ret
=calloc(1,sizeof(*ret
));
455 _sv_tokenval
*_sv_tokenize_parameter(char *in
){
458 char *a
= strdup(in
);
459 _sv_tokenval
*ret
= NULL
;
462 char *l
=split(a
,'=');
464 ret
= _sv_tokenize_flag(a
);
466 ret
= _sv_tokenize_number(l
);
468 char *label
= _sv_tokenize_string(a
);
469 if(ret
->s
) free(ret
->s
);
481 _sv_token
*_sv_tokenize_parameterlist(char *in
){
487 int i
,n
= splitcount(l
,',');
488 _sv_token
*ret
= calloc(1,sizeof(*ret
));
491 ret
->values
= calloc(n
,sizeof(*ret
->values
));
494 char *next
= split(l
,',');
495 ret
->values
[i
] = _sv_tokenize_parameter(l
);
503 _sv_token
*_sv_tokenize_valuelist(char *in
){
509 int i
,n
= splitcount(l
,',');
510 _sv_token
*ret
= calloc(1,sizeof(*ret
));
513 ret
->values
= calloc(n
,sizeof(*ret
->values
));
516 char *next
= split(l
,',');
517 ret
->values
[i
] = _sv_tokenize_displayvalue(l
);
525 _sv_token
*_sv_tokenize_nameparam(char *in
){
526 _sv_token
*ret
= NULL
;
531 // single arg; ignore anything following a level 0 comma
533 fprintf(stderr
,"sushivision: ignoring trailing garbage after \"%s\".\n",a
);
538 if(*a
=='\0')goto done
;
539 ret
= _sv_tokenize_name(a
);
542 _sv_token
*l
= _sv_tokenize_parameterlist(p
);
545 ret
->values
= l
->values
;
558 _sv_token
*_sv_tokenize_declparam(char *in
){
559 _sv_token
*ret
= NULL
;
564 // single arg; ignore anything following a level 0 comma
566 fprintf(stderr
,"sushivision: ignoring trailing garbage after \"%s\".\n",a
);
571 if(*a
=='\0')goto done
;
572 ret
= _sv_tokenize_labelname(a
);
575 _sv_token
*l
= _sv_tokenize_parameterlist(p
);
578 ret
->values
= l
->values
;
591 _sv_tokenlist
*_sv_tokenize_namelist(char *in
){
597 int i
,n
= splitcount(l
,',');
598 _sv_tokenlist
*ret
= calloc(1,sizeof(*ret
));
601 ret
->list
= calloc(n
,sizeof(*ret
->list
));
604 char *next
= split(l
,',');
605 ret
->list
[i
] = _sv_tokenize_nameparam(l
);
613 _sv_tokenlist
*_sv_tokenize_noparamlist(char *in
){
619 int i
,n
= splitcount(l
,',');
620 _sv_tokenlist
*ret
= calloc(1,sizeof(*ret
));
623 ret
->list
= calloc(n
,sizeof(*ret
->list
));
626 char *next
= split(l
,',');
627 ret
->list
[i
] = _sv_tokenize_name(l
);