1 /*****************************************************************************
2 * rpn.c : RPN evaluator for the HTTP Interface
3 *****************************************************************************
4 * Copyright (C) 2001-2005 the VideoLAN team
5 * $Id: http.c 12225 2005-08-18 10:01:30Z massiot $
7 * Authors: Gildas Bazin <gbazin@netcourrier.com>
8 * Laurent Aimar <fenrir@via.ecp.fr>
9 * Christophe Massiot <massiot@via.ecp.fr>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
28 void SSInit( rpn_stack_t *st )
33 void SSClean( rpn_stack_t *st )
35 while( st->i_stack > 0 )
37 free( st->stack[--st->i_stack] );
41 void SSPush( rpn_stack_t *st, const char *s )
43 if( st->i_stack < STACK_MAX )
45 st->stack[st->i_stack++] = strdup( s );
49 char * SSPop( rpn_stack_t *st )
51 if( st->i_stack <= 0 )
57 return st->stack[--st->i_stack];
61 int SSPopN( rpn_stack_t *st, mvar_t *vars )
70 i = strtol( name, &end, 0 );
73 value = mvar_GetValue( vars, name );
81 void SSPushN( rpn_stack_t *st, int i )
85 sprintf( v, "%d", i );
89 void EvaluateRPN( intf_thread_t *p_intf, mvar_t *vars,
90 rpn_stack_t *st, char *exp )
92 intf_sys_t *p_sys = p_intf->p_sys;
94 while( exp != NULL && *exp != '\0' )
107 p = E_(FirstWord)( exp, exp );
114 p = E_(FirstWord)( exp, exp );
118 exp += strlen( exp );
130 /* 1. Integer function */
131 if( !strcmp( s, "!" ) )
133 SSPushN( st, ~SSPopN( st, vars ) );
135 else if( !strcmp( s, "^" ) )
137 SSPushN( st, SSPopN( st, vars ) ^ SSPopN( st, vars ) );
139 else if( !strcmp( s, "&" ) )
141 SSPushN( st, SSPopN( st, vars ) & SSPopN( st, vars ) );
143 else if( !strcmp( s, "|" ) )
145 SSPushN( st, SSPopN( st, vars ) | SSPopN( st, vars ) );
147 else if( !strcmp( s, "+" ) )
149 SSPushN( st, SSPopN( st, vars ) + SSPopN( st, vars ) );
151 else if( !strcmp( s, "-" ) )
153 int j = SSPopN( st, vars );
154 int i = SSPopN( st, vars );
155 SSPushN( st, i - j );
157 else if( !strcmp( s, "*" ) )
159 SSPushN( st, SSPopN( st, vars ) * SSPopN( st, vars ) );
161 else if( !strcmp( s, "/" ) )
165 j = SSPopN( st, vars );
166 i = SSPopN( st, vars );
168 SSPushN( st, j != 0 ? i / j : 0 );
170 else if( !strcmp( s, "%" ) )
174 j = SSPopN( st, vars );
175 i = SSPopN( st, vars );
177 SSPushN( st, j != 0 ? i % j : 0 );
179 /* 2. integer tests */
180 else if( !strcmp( s, "=" ) )
182 SSPushN( st, SSPopN( st, vars ) == SSPopN( st, vars ) ? -1 : 0 );
184 else if( !strcmp( s, "!=" ) )
186 SSPushN( st, SSPopN( st, vars ) != SSPopN( st, vars ) ? -1 : 0 );
188 else if( !strcmp( s, "<" ) )
190 int j = SSPopN( st, vars );
191 int i = SSPopN( st, vars );
193 SSPushN( st, i < j ? -1 : 0 );
195 else if( !strcmp( s, ">" ) )
197 int j = SSPopN( st, vars );
198 int i = SSPopN( st, vars );
200 SSPushN( st, i > j ? -1 : 0 );
202 else if( !strcmp( s, "<=" ) )
204 int j = SSPopN( st, vars );
205 int i = SSPopN( st, vars );
207 SSPushN( st, i <= j ? -1 : 0 );
209 else if( !strcmp( s, ">=" ) )
211 int j = SSPopN( st, vars );
212 int i = SSPopN( st, vars );
214 SSPushN( st, i >= j ? -1 : 0 );
216 /* 3. string functions */
217 else if( !strcmp( s, "strcat" ) )
219 char *s2 = SSPop( st );
220 char *s1 = SSPop( st );
221 char *str = malloc( strlen( s1 ) + strlen( s2 ) + 1 );
231 else if( !strcmp( s, "strcmp" ) )
233 char *s2 = SSPop( st );
234 char *s1 = SSPop( st );
236 SSPushN( st, strcmp( s1, s2 ) );
240 else if( !strcmp( s, "strncmp" ) )
242 int n = SSPopN( st, vars );
243 char *s2 = SSPop( st );
244 char *s1 = SSPop( st );
246 SSPushN( st, strncmp( s1, s2 , n ) );
250 else if( !strcmp( s, "strsub" ) )
252 int n = SSPopN( st, vars );
253 int m = SSPopN( st, vars );
255 char *s = SSPop( st );
267 str = malloc( i_len + 1 );
269 memcpy( str, s + m - 1, i_len );
276 else if( !strcmp( s, "strlen" ) )
278 char *str = SSPop( st );
280 SSPushN( st, strlen( str ) );
283 else if( !strcmp( s, "str_replace" ) )
285 char *psz_to = SSPop( st );
286 char *psz_from = SSPop( st );
287 char *psz_in = SSPop( st );
288 char *psz_in_current = psz_in;
289 char *psz_out = malloc( strlen(psz_in) * strlen(psz_to) + 1 );
290 char *psz_out_current = psz_out;
292 while( (p = strstr( psz_in_current, psz_from )) != NULL )
294 memcpy( psz_out_current, psz_in_current, p - psz_in_current );
295 psz_out_current += p - psz_in_current;
296 strcpy( psz_out_current, psz_to );
297 psz_out_current += strlen(psz_to);
298 psz_in_current = p + strlen(psz_from);
300 strcpy( psz_out_current, psz_in_current );
301 psz_out_current += strlen(psz_in_current);
302 *psz_out_current = '\0';
304 SSPush( st, psz_out );
310 else if( !strcmp( s, "url_extract" ) )
312 char *url = mvar_GetValue( vars, "url_value" );
313 char *name = SSPop( st );
317 E_(ExtractURIValue)( url, name, value, 512 );
318 E_(DecodeEncodedURI)( value );
319 tmp = E_(FromUTF8)( p_intf, value );
324 else if( !strcmp( s, "url_encode" ) )
326 char *url = SSPop( st );
329 value = E_(ToUTF8)( p_intf, url );
332 value = vlc_UrlEncode( url );
337 else if( !strcmp( s, "addslashes" ) )
339 char *psz_src = SSPop( st );
343 p = psz_dest = malloc( strlen( str ) * 2 + 1 );
345 while( *str != '\0' )
347 if( *str == '"' || *str == '\'' )
356 SSPush( st, psz_dest );
360 else if( !strcmp( s, "stripslashes" ) )
362 char *psz_src = SSPop( st );
365 p = psz_dest = strdup( psz_src );
367 while( *psz_src != '\0' )
369 if( *psz_src == '\\' )
378 SSPush( st, psz_dest );
382 else if( !strcmp( s, "htmlspecialchars" ) )
384 char *psz_src = SSPop( st );
388 p = psz_dest = malloc( strlen( str ) * 6 + 1 );
390 while( *str != '\0' )
394 strcpy( p, "&" );
397 else if( *str == '\"' )
399 strcpy( p, """ );
402 else if( *str == '\'' )
404 strcpy( p, "'" );
407 else if( *str == '<' )
412 else if( *str == '>' )
425 SSPush( st, psz_dest );
429 else if( !strcmp( s, "realpath" ) )
431 char dir[MAX_DIR_SIZE], *src;
432 char *psz_src = SSPop( st );
433 char *psz_dir = psz_src;
436 /* convert all / to native separator */
438 while( (p = strchr( psz_dir, '/' )) )
447 if( *psz_dir == '~' )
449 /* This is incomplete : we should also support the ~cmassiot/ syntax. */
450 snprintf( dir, sizeof(dir), "%s/%s", p_intf->p_vlc->psz_homedir,
455 /* first fix all .. dir */
459 if( src[0] == '.' && src[1] == '.' )
462 if( p <= &psz_dir[1] )
469 while( p > &psz_dir[1] && *p != sep )
474 else if( *src == sep )
476 if( p > psz_dir && p[-1] == sep )
490 } while( *src && *src != sep );
493 if( p != psz_dir + 1 && p[-1] == '/' ) p--;
496 SSPush( st, psz_dir );
499 /* 4. stack functions */
500 else if( !strcmp( s, "dup" ) )
502 char *str = SSPop( st );
507 else if( !strcmp( s, "drop" ) )
509 char *str = SSPop( st );
512 else if( !strcmp( s, "swap" ) )
514 char *s1 = SSPop( st );
515 char *s2 = SSPop( st );
522 else if( !strcmp( s, "flush" ) )
527 else if( !strcmp( s, "store" ) )
529 char *value = SSPop( st );
530 char *name = SSPop( st );
532 mvar_PushNewVar( vars, name, value );
536 else if( !strcmp( s, "value" ) )
538 char *name = SSPop( st );
539 char *value = mvar_GetValue( vars, name );
545 /* 5. player control */
546 else if( !strcmp( s, "vlc_play" ) )
548 int i_id = SSPopN( st, vars );
551 i_ret = playlist_Control( p_sys->p_playlist, PLAYLIST_ITEMPLAY,
552 playlist_ItemGetById( p_sys->p_playlist,
554 msg_Dbg( p_intf, "requested playlist item: %i", i_id );
555 SSPushN( st, i_ret );
557 else if( !strcmp( s, "vlc_stop" ) )
559 playlist_Control( p_sys->p_playlist, PLAYLIST_STOP );
560 msg_Dbg( p_intf, "requested playlist stop" );
562 else if( !strcmp( s, "vlc_pause" ) )
564 playlist_Control( p_sys->p_playlist, PLAYLIST_PAUSE );
565 msg_Dbg( p_intf, "requested playlist pause" );
567 else if( !strcmp( s, "vlc_next" ) )
569 playlist_Control( p_sys->p_playlist, PLAYLIST_SKIP, 1 );
570 msg_Dbg( p_intf, "requested playlist next" );
572 else if( !strcmp( s, "vlc_previous" ) )
574 playlist_Control( p_sys->p_playlist, PLAYLIST_SKIP, -1 );
575 msg_Dbg( p_intf, "requested playlist previous" );
577 else if( !strcmp( s, "vlc_seek" ) )
579 char *psz_value = SSPop( st );
580 E_(HandleSeek)( p_intf, psz_value );
581 msg_Dbg( p_intf, "requested playlist seek: %s", psz_value );
584 else if( !strcmp( s, "vlc_var_type" )
585 || !strcmp( s, "vlc_config_type" ) )
587 const char *psz_type = NULL;
588 char *psz_variable = SSPop( st );
589 vlc_object_t *p_object;
592 if( !strcmp( s, "vlc_var_type" ) )
594 p_object = VLC_OBJECT(p_sys->p_input);
595 if( p_object != NULL )
596 i_type = var_Type( p_object, psz_variable );
600 p_object = VLC_OBJECT(p_intf);
601 i_type = config_GetType( p_object, psz_variable );
604 if( p_object != NULL )
606 switch( i_type & VLC_VAR_TYPE )
609 psz_type = "VLC_VAR_BOOL";
611 case VLC_VAR_INTEGER:
612 psz_type = "VLC_VAR_INTEGER";
615 psz_type = "VLC_VAR_HOTKEY";
618 psz_type = "VLC_VAR_STRING";
621 psz_type = "VLC_VAR_MODULE";
624 psz_type = "VLC_VAR_FILE";
626 case VLC_VAR_DIRECTORY:
627 psz_type = "VLC_VAR_DIRECTORY";
629 case VLC_VAR_VARIABLE:
630 psz_type = "VLC_VAR_VARIABLE";
633 psz_type = "VLC_VAR_FLOAT";
636 psz_type = "UNDEFINED";
640 psz_type = "INVALID";
642 SSPush( st, psz_type );
643 free( psz_variable );
645 else if( !strcmp( s, "vlc_var_set" ) )
647 char *psz_variable = SSPop( st );
649 if( p_sys->p_input != NULL )
651 vlc_bool_t b_error = VLC_FALSE;
652 char *psz_value = NULL;
656 i_type = var_Type( p_sys->p_input, psz_variable );
658 switch( i_type & VLC_VAR_TYPE )
661 val.b_bool = SSPopN( st, vars );
662 msg_Dbg( p_intf, "requested input var change: %s->%d",
663 psz_variable, val.b_bool );
665 case VLC_VAR_INTEGER:
667 val.i_int = SSPopN( st, vars );
668 msg_Dbg( p_intf, "requested input var change: %s->%d",
669 psz_variable, val.i_int );
674 case VLC_VAR_DIRECTORY:
675 case VLC_VAR_VARIABLE:
676 val.psz_string = psz_value = SSPop( st );
677 msg_Dbg( p_intf, "requested input var change: %s->%s",
678 psz_variable, psz_value );
681 psz_value = SSPop( st );
682 val.f_float = atof( psz_value );
683 msg_Dbg( p_intf, "requested input var change: %s->%f",
684 psz_variable, val.f_float );
687 msg_Warn( p_intf, "invalid variable type %d (%s)",
688 i_type & VLC_VAR_TYPE, psz_variable );
693 var_Set( p_sys->p_input, psz_variable, val );
694 if( psz_value != NULL )
698 msg_Warn( p_intf, "vlc_var_set called without an input" );
699 free( psz_variable );
701 else if( !strcmp( s, "vlc_var_get" ) )
703 char *psz_variable = SSPop( st );
705 if( p_sys->p_input != NULL )
710 i_type = var_Type( p_sys->p_input, psz_variable );
711 var_Get( p_sys->p_input, psz_variable, &val );
713 switch( i_type & VLC_VAR_TYPE )
716 SSPushN( st, val.b_bool );
718 case VLC_VAR_INTEGER:
720 SSPushN( st, val.i_int );
725 case VLC_VAR_DIRECTORY:
726 case VLC_VAR_VARIABLE:
727 SSPush( st, val.psz_string );
728 free( val.psz_string );
733 snprintf( psz_value, sizeof(psz_value), "%f", val.f_float );
734 SSPush( st, psz_value );
738 msg_Warn( p_intf, "invalid variable type %d (%s)",
739 i_type & VLC_VAR_TYPE, psz_variable );
745 msg_Warn( p_intf, "vlc_var_get called without an input" );
748 free( psz_variable );
750 else if( !strcmp( s, "vlc_config_set" ) )
752 char *psz_variable = SSPop( st );
753 int i_type = config_GetType( p_intf, psz_variable );
755 switch( i_type & VLC_VAR_TYPE )
758 case VLC_VAR_INTEGER:
759 config_PutInt( p_intf, psz_variable, SSPopN( st, vars ) );
764 case VLC_VAR_DIRECTORY:
766 char *psz_string = SSPop( st );
767 config_PutPsz( p_intf, psz_variable, psz_string );
773 char *psz_string = SSPop( st );
774 config_PutFloat( p_intf, psz_variable, atof(psz_string) );
779 msg_Warn( p_intf, "vlc_config_set called on unknown var (%s)",
782 free( psz_variable );
784 else if( !strcmp( s, "vlc_config_get" ) )
786 char *psz_variable = SSPop( st );
787 int i_type = config_GetType( p_intf, psz_variable );
789 switch( i_type & VLC_VAR_TYPE )
792 case VLC_VAR_INTEGER:
793 SSPushN( st, config_GetInt( p_intf, psz_variable ) );
798 case VLC_VAR_DIRECTORY:
800 char *psz_string = config_GetPsz( p_intf, psz_variable );
801 SSPush( st, psz_string );
808 snprintf( psz_string, sizeof(psz_string), "%f",
809 config_GetFloat( p_intf, psz_variable ) );
810 SSPush( st, psz_string );
814 msg_Warn( p_intf, "vlc_config_get called on unknown var (%s)",
817 free( psz_variable );
819 else if( !strcmp( s, "vlc_config_save" ) )
821 char *psz_module = SSPop( st );
829 i_result = config_SaveConfigFile( p_intf, psz_module );
831 if( psz_module != NULL )
833 SSPushN( st, i_result );
835 else if( !strcmp( s, "vlc_config_reset" ) )
837 config_ResetAll( p_intf );
839 /* 6. playlist functions */
840 else if( !strcmp( s, "playlist_add" ) )
842 char *psz_name = SSPop( st );
843 char *mrl = SSPop( st );
845 playlist_item_t *p_item;
848 tmp = E_(ToUTF8)( p_intf, psz_name );
851 tmp = E_(ToUTF8)( p_intf, mrl );
857 p_item = E_(MRLParse)( p_intf, mrl, mrl );
861 p_item = E_(MRLParse)( p_intf, mrl, psz_name );
864 if( p_item == NULL || p_item->input.psz_uri == NULL ||
865 !*p_item->input.psz_uri )
868 msg_Dbg( p_intf, "invalid requested mrl: %s", mrl );
872 i_id = playlist_AddItem( p_sys->p_playlist, p_item,
873 PLAYLIST_APPEND, PLAYLIST_END );
874 msg_Dbg( p_intf, "requested mrl add: %s", mrl );
881 else if( !strcmp( s, "playlist_empty" ) )
883 playlist_LockClear( p_sys->p_playlist );
884 msg_Dbg( p_intf, "requested playlist empty" );
886 else if( !strcmp( s, "playlist_delete" ) )
888 int i_id = SSPopN( st, vars );
889 playlist_LockDelete( p_sys->p_playlist, i_id );
890 msg_Dbg( p_intf, "requested playlist delete: %d", i_id );
892 else if( !strcmp( s, "playlist_move" ) )
894 int i_newpos = SSPopN( st, vars );
895 int i_pos = SSPopN( st, vars );
896 if ( i_pos < i_newpos )
898 playlist_Move( p_sys->p_playlist, i_pos, i_newpos + 1 );
902 playlist_Move( p_sys->p_playlist, i_pos, i_newpos );
904 msg_Dbg( p_intf, "requested to move playlist item %d to %d",