]> git.sesse.net Git - vlc/blob - src/interface/interface.c
many minor style fixes (thanx to sam).
[vlc] / src / interface / interface.c
1 /*****************************************************************************
2  * interface.c: interface access for other threads
3  * This library provides basic functions for threads to interact with user
4  * interface, such as command line.
5  *****************************************************************************
6  * Copyright (C) 1998, 1999, 2000 VideoLAN
7  *
8  * Authors:
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include "defs.h"
29
30 #include <errno.h>                                                 /* ENOMEM */
31 #include <stdlib.h>                                      /* free(), strtol() */
32 #include <stdio.h>                                                   /* FILE */
33 #include <string.h>                                            /* strerror() */
34 #include <sys/types.h>                        /* on BSD, uio.h needs types.h */
35 #include <sys/uio.h>                                          /* for input.h */
36
37 #include "config.h"
38 #include "common.h"
39 #include "threads.h"
40 #include "mtime.h"
41 #include "plugins.h"
42 #include "playlist.h"
43 #include "input.h"
44
45 #include "audio_output.h"
46
47 #include "intf_msg.h"
48 #include "interface.h"
49 #include "intf_cmd.h"
50 #include "intf_console.h"
51 #include "keystrokes.h"
52
53 #include "video.h"
54 #include "video_output.h"
55
56 #include "main.h"
57
58 /*****************************************************************************
59  * intf_channel_t: channel description
60  *****************************************************************************
61  * A 'channel' is a descriptor of an input method. It is used to switch easily
62  * from source to source without having to specify the whole input thread
63  * configuration. The channels array, stored in the interface thread object, is
64  * loaded in intf_Create, and unloaded in intf_Destroy.
65  *****************************************************************************/
66 typedef struct intf_channel_s
67 {
68     /* Channel description */
69     int         i_channel;            /* channel number, -1 for end of array */
70     char *      psz_description;              /* channel description (owned) */
71
72     /* Input configuration */
73     int         i_input_method;                   /* input method descriptor */
74     char *      psz_input_source;                   /* source string (owned) */
75     int         i_input_port;                                        /* port */
76     int         i_input_vlan;                                        /* vlan */
77 } intf_channel_t;
78
79 /*****************************************************************************
80  * Local prototypes
81  *****************************************************************************/
82 static int      LoadChannels    ( intf_thread_t *p_intf, char *psz_filename );
83 static void     UnloadChannels  ( intf_thread_t *p_intf );
84 static int      ParseChannel    ( intf_channel_t *p_channel, char *psz_str );
85
86 /*****************************************************************************
87  * intf_Create: prepare interface before main loop
88  *****************************************************************************
89  * This function opens output devices and creates specific interfaces. It sends
90  * its own error messages.
91  *****************************************************************************/
92 intf_thread_t* intf_Create( void )
93 {
94     intf_thread_t * p_intf;
95     typedef void    ( intf_getplugin_t ) ( intf_thread_t * p_intf );
96     int             i_index;
97     int             i_best_index = 0, i_best_score = 0;
98
99     /* Allocate structure */
100     p_intf = malloc( sizeof( intf_thread_t ) );
101     if( !p_intf )
102     {
103         intf_ErrMsg("error: %s\n", strerror( ENOMEM ) );
104         return( NULL );
105     }
106
107     /* Get a suitable interface plugin */
108     for( i_index = 0 ; i_index < p_main->p_bank->i_plugin_count ; i_index++ )
109     {
110         /* If there's a plugin in p_info ... */
111         if( p_main->p_bank->p_info[ i_index ] != NULL )
112         {
113             /* ... and if this plugin provides the functions we want ... */
114             if( p_main->p_bank->p_info[ i_index ]->intf_GetPlugin != NULL )
115             {
116                 /* ... and if this plugin has a good score ... */
117                 if( p_main->p_bank->p_info[ i_index ]->i_score > i_best_score )
118                 {
119                     /* ... then take it */
120                     i_best_score = p_main->p_bank->p_info[ i_index ]->i_score;
121                     i_best_index = i_index;
122                 }
123             }
124         }
125     }
126
127         if( i_best_score == 0 )
128         {
129         free( p_intf );
130         return( NULL );
131         }
132
133         /* Get the plugin functions */
134         ( (intf_getplugin_t *)
135           p_main->p_bank->p_info[ i_best_index ]->intf_GetPlugin )( p_intf );
136
137         /* Initialize structure */
138         p_intf->b_die =     0;
139         p_intf->p_vout =    NULL;
140         p_intf->p_input =   NULL;
141         p_intf->p_keys =    NULL;
142
143         /* Load channels - the pointer will be set to NULL on failure. The
144          * return value is ignored since the program can work without
145          * channels */
146         LoadChannels( p_intf, main_GetPszVariable( INTF_CHANNELS_VAR, INTF_CHANNELS_DEFAULT ));
147
148         /* Start interfaces */
149         p_intf->p_console = intf_ConsoleCreate();
150         if( p_intf->p_console == NULL )
151         {
152         intf_ErrMsg("error: can't create control console\n");
153         free( p_intf );
154         return( NULL );
155         }
156         if( p_intf->p_sys_create( p_intf ) )
157         {
158         intf_ErrMsg("error: can't create interface\n");
159         intf_ConsoleDestroy( p_intf->p_console );
160         free( p_intf );
161         return( NULL );
162         }
163
164         intf_Msg("Interface initialized\n");
165         return( p_intf );
166     }
167
168     /*****************************************************************************
169      * intf_Run
170      *****************************************************************************
171      * Initialization script and main interface loop.
172      *****************************************************************************/
173     void intf_Run( intf_thread_t *p_intf )
174     {
175         if( p_main->p_playlist->p_list )
176         {
177         p_intf->p_input = input_CreateThread( INPUT_METHOD_TS_FILE, NULL, 0, 0, p_main->p_intf->p_vout, p_main->p_aout, NULL );
178         }
179         /* Execute the initialization script - if a positive number is returned,
180          * the script could be executed but failed */
181         else if( intf_ExecScript( main_GetPszVariable( INTF_INIT_SCRIPT_VAR, INTF_INIT_SCRIPT_DEFAULT ) ) > 0 )
182         {
183         intf_ErrMsg("warning: error(s) during startup script\n");
184         }
185
186         /* Main loop */
187         while(!p_intf->b_die)
188         {
189         /* Flush waiting messages */
190         intf_FlushMsg();
191
192         /* Manage specific interface */
193         p_intf->p_sys_manage( p_intf );
194
195         /* Check attached threads status */
196         if( (p_intf->p_vout != NULL) && p_intf->p_vout->b_error )
197         {
198             /* FIXME: add aout error detection ?? */
199             p_intf->b_die = 1;
200         }
201         if( (p_intf->p_input != NULL) && p_intf->p_input->b_error )
202         {
203             input_DestroyThread( p_intf->p_input, NULL );
204             p_intf->p_input = NULL;
205             intf_DbgMsg("Input thread destroyed\n");
206         }
207
208         /* Sleep to avoid using all CPU - since some interfaces needs to access
209          * keyboard events, a 100ms delay is a good compromise */
210         msleep( INTF_IDLE_SLEEP );
211         }
212     }
213
214     /*****************************************************************************
215      * intf_Destroy: clean interface after main loop
216      *****************************************************************************
217      * This function destroys specific interfaces and close output devices.
218      *****************************************************************************/
219     void intf_Destroy( intf_thread_t *p_intf )
220     {
221         p_intf_key  p_cur;
222         p_intf_key  p_next;
223         /* Destroy interfaces */
224         p_intf->p_sys_destroy( p_intf );
225         intf_ConsoleDestroy( p_intf->p_console );
226
227         /* Unload channels */
228         UnloadChannels( p_intf );
229
230         /* Destroy keymap */
231         
232         p_cur = p_intf->p_keys;
233         while( p_cur != NULL)
234         {
235         p_next = p_cur->next;
236         free(p_cur);
237         p_cur = p_next;
238          }
239          
240         
241         /* Free structure */
242         free( p_intf );
243     }
244
245     /*****************************************************************************
246      * intf_SelectChannel: change channel
247      *****************************************************************************
248      * Kill existing input, if any, and try to open a new one, using an input
249      * configuration table.
250      *****************************************************************************/
251     int intf_SelectChannel( intf_thread_t * p_intf, int i_channel )
252     {
253         intf_channel_t *    p_channel;                                /* channel */
254
255         /* Look for channel in array */
256         if( p_intf->p_channel != NULL )
257         {
258         for( p_channel = p_intf->p_channel; p_channel->i_channel != -1; p_channel++ )
259         {
260             if( p_channel->i_channel == i_channel )
261             {
262             /*
263              * Change channel
264              */
265
266             /* Kill existing input, if any */
267             if( p_intf->p_input != NULL )
268             {
269                 input_DestroyThread( p_intf->p_input, NULL );
270             }
271
272             intf_Msg("Channel %d: %s\n", i_channel, p_channel->psz_description );
273
274             /* Open a new input */
275             p_intf->p_input = input_CreateThread( p_channel->i_input_method, p_channel->psz_input_source,
276                                   p_channel->i_input_port, p_channel->i_input_vlan,
277                                   p_intf->p_vout, p_main->p_aout, NULL );
278             return( p_intf->p_input == NULL );
279             }
280         }
281         }
282
283         /* Channel does not exist */
284         intf_Msg("Channel %d does not exist\n", i_channel );
285         return( 1 );
286     }
287
288     /*****************************************************************************
289      * intf_AssignKey: assign standartkeys                                       *
290      *****************************************************************************
291      * This function fills in the associative array that links the key pressed   *
292      * and the key we use internally. Support one extra parameter.               *
293      ****************************************************************************/
294
295 void intf_AssignKey( intf_thread_t *p_intf, int r_key, int f_key, int param)
296 {
297     p_intf_key  p_cur =  p_intf->p_keys;
298     if( p_cur == NULL )
299     {
300         p_cur = (p_intf_key )(malloc ( sizeof( intf_key ) ) );
301         p_cur->received_key = r_key;
302         p_cur->forwarded.key = f_key;
303         p_cur->forwarded.param = param; 
304         p_cur->next = NULL;
305         p_intf->p_keys = p_cur;
306     } 
307     else 
308     {
309         while( p_cur->next != NULL && p_cur ->received_key != r_key)
310         {
311             p_cur = p_cur->next;
312         }
313         if( p_cur->next == NULL )
314         {   
315             p_cur->next  = ( p_intf_key )( malloc( sizeof( intf_key ) ) );
316             p_cur = p_cur->next;
317             p_cur->next = NULL;
318             p_cur->forwarded.param = param; 
319             p_cur->received_key = r_key;
320         }
321         p_cur->forwarded.key = f_key;
322     }        
323 }
324
325 /* Basic getKey function... */
326 keyparm intf_getKey( intf_thread_t *p_intf, int r_key)
327 {   
328     keyparm reply;
329     
330     p_intf_key current = p_intf->p_keys;
331     while(current != NULL && current->received_key != r_key)
332     {    
333         current = current->next;
334     }
335     if(current == NULL)
336     {   /* didn't find any key in the array */ 
337         reply.key=INTF_KEY_UNKNOWN;
338         reply.param=0;
339     }
340     else
341     {
342         reply.key = current->forwarded.key;
343         reply.param = current->forwarded.param;
344     }
345     return reply;
346 }
347
348 /*****************************************************************************
349 * intf_AssignNormalKeys: used for normal interfaces.
350 *****************************************************************************
351 * This function assign the basic key to the normal keys.
352 *****************************************************************************/
353
354 void intf_AssignNormalKeys( intf_thread_t *p_intf)
355 {
356     p_intf->p_intf_getKey = intf_getKey;
357
358     intf_AssignKey( p_intf , 'Q', INTF_KEY_QUIT, 0);
359     intf_AssignKey( p_intf , 'q', INTF_KEY_QUIT, 0);
360     intf_AssignKey( p_intf ,  27, INTF_KEY_QUIT, 0);
361     intf_AssignKey( p_intf ,   3, INTF_KEY_QUIT, 0);
362     intf_AssignKey( p_intf , '0', INTF_KEY_SET_CHANNEL, 0);
363     intf_AssignKey( p_intf , '1', INTF_KEY_SET_CHANNEL, 1);
364     intf_AssignKey( p_intf , '2', INTF_KEY_SET_CHANNEL, 2);
365     intf_AssignKey( p_intf , '3', INTF_KEY_SET_CHANNEL, 3);
366     intf_AssignKey( p_intf , '4', INTF_KEY_SET_CHANNEL, 4);
367     intf_AssignKey( p_intf , '5', INTF_KEY_SET_CHANNEL, 5);
368     intf_AssignKey( p_intf , '6', INTF_KEY_SET_CHANNEL, 6);
369     intf_AssignKey( p_intf , '7', INTF_KEY_SET_CHANNEL, 7);
370     intf_AssignKey( p_intf , '8', INTF_KEY_SET_CHANNEL, 8);
371     intf_AssignKey( p_intf , '9', INTF_KEY_SET_CHANNEL, 9);
372     intf_AssignKey( p_intf , '0', INTF_KEY_SET_CHANNEL, 0);
373     intf_AssignKey( p_intf , '+', INTF_KEY_INC_VOLUME, 0);
374     intf_AssignKey( p_intf , '-', INTF_KEY_DEC_VOLUME, 0);
375     intf_AssignKey( p_intf , 'm', INTF_KEY_TOGGLE_VOLUME, 0);
376     intf_AssignKey( p_intf , 'M', INTF_KEY_TOGGLE_VOLUME, 0);
377     intf_AssignKey( p_intf , 'g', INTF_KEY_DEC_GAMMA, 0);
378     intf_AssignKey( p_intf , 'G', INTF_KEY_INC_GAMMA, 0);
379     intf_AssignKey( p_intf , 'c', INTF_KEY_TOGGLE_GRAYSCALE, 0);
380     intf_AssignKey( p_intf , ' ', INTF_KEY_TOGGLE_INTERFACE, 0);
381     intf_AssignKey( p_intf , 'i', INTF_KEY_TOGGLE_INFO, 0);
382     intf_AssignKey( p_intf , 's', INTF_KEY_TOGGLE_SCALING, 0);
383 }   
384
385 /*****************************************************************************
386  * intf_ProcessKey: process standard keys
387  *****************************************************************************
388  * This function will process standard keys and return non 0 if the key was
389  * unknown.
390  *****************************************************************************/
391 int intf_ProcessKey( intf_thread_t *p_intf, int g_key )
392 {
393     static int i_volbackup;
394     keyparm k_reply;
395     
396     k_reply = intf_getKey( p_intf, g_key); 
397     
398     switch( k_reply.key )
399     {
400     case INTF_KEY_QUIT:                                                  /* quit order */
401         p_intf->b_die = 1;
402         break;
403     case INTF_KEY_SET_CHANNEL:
404         /* Change channel - return code is ignored since SelectChannel displays
405          * its own error messages */
406         intf_SelectChannel( p_intf, k_reply.param - '0' );
407         break;
408     case INTF_KEY_INC_VOLUME:                                                    /* volume + */
409         if( (p_main->p_aout != NULL) && (p_main->p_aout->vol < VOLMAX) )
410             p_main->p_aout->vol += VOLSTEP;
411         break;
412     case INTF_KEY_DEC_VOLUME:                                                    /* volume - */
413         if( (p_main->p_aout != NULL) && (p_main->p_aout->vol > VOLSTEP) )
414             p_main->p_aout->vol -= VOLSTEP;
415         break;
416     case INTF_KEY_TOGGLE_VOLUME:                                                 /* toggle mute */
417         if( (p_main->p_aout != NULL) && (p_main->p_aout->vol))
418         {
419             i_volbackup = p_main->p_aout->vol;
420             p_main->p_aout->vol = 0;
421         }
422         else if( (p_main->p_aout != NULL) && (!p_main->p_aout->vol))
423             p_main->p_aout->vol = i_volbackup;
424         break;
425     case INTF_KEY_DEC_GAMMA:                                                     /* gamma - */
426         if( (p_intf->p_vout != NULL) && (p_intf->p_vout->f_gamma > -INTF_GAMMA_LIMIT) )
427         {
428             vlc_mutex_lock( &p_intf->p_vout->change_lock );
429             p_intf->p_vout->f_gamma   -= INTF_GAMMA_STEP;
430             p_intf->p_vout->i_changes |= VOUT_GAMMA_CHANGE;
431             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
432         }
433         break;
434     case INTF_KEY_INC_GAMMA:                                                     /* gamma + */
435         if( (p_intf->p_vout != NULL) && (p_intf->p_vout->f_gamma < INTF_GAMMA_LIMIT) )
436         {
437             vlc_mutex_lock( &p_intf->p_vout->change_lock );
438             p_intf->p_vout->f_gamma   += INTF_GAMMA_STEP;
439             p_intf->p_vout->i_changes |= VOUT_GAMMA_CHANGE;
440             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
441         }
442         break;
443     case INTF_KEY_TOGGLE_GRAYSCALE:                                            /* toggle grayscale */
444         if( p_intf->p_vout != NULL )
445         {
446             vlc_mutex_lock( &p_intf->p_vout->change_lock );
447             p_intf->p_vout->b_grayscale = !p_intf->p_vout->b_grayscale;
448             p_intf->p_vout->i_changes  |= VOUT_GRAYSCALE_CHANGE;
449             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
450         }
451         break;
452     case INTF_KEY_TOGGLE_INTERFACE:                                            /* toggle interface */
453         if( p_intf->p_vout != NULL )
454         {
455             vlc_mutex_lock( &p_intf->p_vout->change_lock );
456             p_intf->p_vout->b_interface     = !p_intf->p_vout->b_interface;
457             p_intf->p_vout->i_changes |= VOUT_INTF_CHANGE;
458             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
459         }
460         break;
461     case INTF_KEY_TOGGLE_INFO:                                                 /* toggle info */
462         if( p_intf->p_vout != NULL )
463         {
464             vlc_mutex_lock( &p_intf->p_vout->change_lock );
465             p_intf->p_vout->b_info     = !p_intf->p_vout->b_info;
466             p_intf->p_vout->i_changes |= VOUT_INFO_CHANGE;
467             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
468         }
469         break;
470     case INTF_KEY_TOGGLE_SCALING:                                              /* toggle scaling */
471         if( p_intf->p_vout != NULL )
472         {
473             vlc_mutex_lock( &p_intf->p_vout->change_lock );
474             p_intf->p_vout->b_scale    = !p_intf->p_vout->b_scale;
475             p_intf->p_vout->i_changes |= VOUT_SCALE_CHANGE;
476             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
477         }
478         break;
479    default:                                                   /* unknown key */
480         return( 1 );
481     }
482
483     return( 0 );
484 }
485
486 /* following functions are local */
487
488 /*****************************************************************************
489  * LoadChannels: load channels description from a file
490  *****************************************************************************
491  * This structe describes all interface-specific data of the main (interface)
492  * thread.
493  * Each line of the file is a semicolon separated list of the following
494  * fields :
495  *      integer         channel number
496  *      string          channel description
497  *      integer         input method (see input.h)
498  *      string          input source
499  *      integer         input port
500  *      integer         input vlan
501  * The last field must end with a semicolon.
502  * Comments and empty lines are not explicitely allowed, but lines with parsing
503  * errors are ignored without warning.
504  *****************************************************************************/
505 static int LoadChannels( intf_thread_t *p_intf, char *psz_filename )
506 {
507     FILE *              p_file;                                      /* file */
508     intf_channel_t *    p_channel;                        /* current channel */
509     char                psz_line[INTF_MAX_CMD_SIZE];          /* line buffer */
510     int                 i_index;                   /* channel or field index */
511
512     /* Set default value */
513     p_intf->p_channel = NULL;
514
515     /* FIXME: channels are disabled */
516     return( 0 );
517
518     /* Open file */
519     p_file = fopen( psz_filename, "r" );
520     if( p_file == NULL )
521     {
522         intf_ErrMsg("error: can't open %s (%s)\n", psz_filename, strerror(errno));
523         return( 1 );
524     }
525
526     /* First pass: count number of lines */
527     for( i_index = 0; fgets( psz_line, INTF_MAX_CMD_SIZE, p_file ) != NULL; i_index++ )
528     {
529         ;
530     }
531
532     if( i_index != 0 )
533     {
534         /* Allocate array and rewind - some of the lines may be invalid, and the
535          * array will probably be larger than the actual number of channels, but
536          * it has no consequence. */
537         p_intf->p_channel = malloc( sizeof( intf_channel_t ) * i_index );
538         if( p_intf->p_channel == NULL )
539         {
540             intf_ErrMsg("error: %s\n", strerror(ENOMEM));
541             fclose( p_file );
542             return( 1 );
543         }
544         p_channel = p_intf->p_channel;
545         rewind( p_file );
546
547         /* Second pass: read channels descriptions */
548         while( fgets( psz_line, INTF_MAX_CMD_SIZE, p_file ) != NULL )
549         {
550             if( !ParseChannel( p_channel, psz_line ) )
551             {
552                 intf_DbgMsg( "channel [%d] %s : method %d (%s:%d vlan %d)\n",
553                          p_channel->i_channel, p_channel->psz_description,
554                          p_channel->i_input_method,
555                          p_channel->psz_input_source,
556                          p_channel->i_input_port, p_channel->i_input_vlan );
557                 p_channel++;
558             }
559         }
560
561         /* Add marker at the end of the array */
562         p_channel->i_channel = -1;
563     }
564
565     /* Close file */
566     fclose( p_file );
567     return( 0 );
568 }
569
570 /*****************************************************************************
571  * UnloadChannels: unload channels description
572  *****************************************************************************
573  * This function free all resources allocated by LoadChannels, if any.
574  *****************************************************************************/
575 static void UnloadChannels( intf_thread_t *p_intf )
576 {
577     int i_channel;                                          /* channel index */
578
579     if( p_intf->p_channel != NULL )
580     {
581         /* Free allocated strings */
582         for( i_channel = 0;
583              p_intf->p_channel[ i_channel ].i_channel != -1;
584              i_channel++ )
585         {
586             if( p_intf->p_channel[ i_channel ].psz_description != NULL )
587             {
588                 free( p_intf->p_channel[ i_channel ].psz_description );
589             }
590             if( p_intf->p_channel[ i_channel ].psz_input_source != NULL )
591             {
592                 free( p_intf->p_channel[ i_channel ].psz_input_source );
593             }
594         }
595
596         /* Free array */
597         free( p_intf->p_channel );
598         p_intf->p_channel = NULL;
599     }
600 }
601
602
603 /*****************************************************************************
604  * ParseChannel: parse a channel description line
605  *****************************************************************************
606  * See LoadChannels. This function return non 0 on parsing error.
607  *****************************************************************************/
608 static int ParseChannel( intf_channel_t *p_channel, char *psz_str )
609 {
610     char *      psz_index;                              /* current character */
611     char *      psz_end;                           /* end pointer for strtol */
612     int         i_field;                        /* field number, -1 on error */
613     int         i_field_length;             /* field length, for text fields */
614
615     /* Set some default fields */
616     p_channel->i_channel =              0;
617     p_channel->psz_description =        NULL;
618     p_channel->i_input_method =         0;
619     p_channel->psz_input_source =       NULL;
620     p_channel->i_input_port =           0;
621     p_channel->i_input_vlan =           0;
622
623     /* Parse string */
624     i_field = 0;
625     for( psz_index = psz_str; (i_field != -1) && (*psz_index != '\0'); psz_index++ )
626     {
627         if( *psz_index == ';' )
628         {
629             /* Mark end of field */
630             *psz_index = '\0';
631
632             /* Parse field */
633             switch( i_field++ )
634             {
635             case 0:                                        /* channel number */
636                 p_channel->i_channel = strtol( psz_str, &psz_end, 0);
637                 if( (*psz_str == '\0') || (*psz_end != '\0') )
638                 {
639                     i_field = -1;
640                 }
641                 break;
642             case 1:                                   /* channel description */
643                 i_field_length = strlen( psz_str );
644                 if( i_field_length != 0 )
645                 {
646                     p_channel->psz_description = malloc( i_field_length + 1 );
647                     if( p_channel->psz_description == NULL )
648                     {
649                         intf_ErrMsg("error: %s\n", strerror( ENOMEM ));
650                         i_field = -1;
651                     }
652                     else
653                     {
654                         strcpy( p_channel->psz_description, psz_str );
655                     }
656                 }
657                 break;
658             case 2:                                          /* input method */
659                 p_channel->i_input_method = strtol( psz_str, &psz_end, 0);
660                 if( (*psz_str == '\0') || (*psz_end != '\0') )
661                 {
662                     i_field = -1;
663                 }
664                 break;
665             case 3:                                          /* input source */
666                 i_field_length = strlen( psz_str );
667                 if( i_field_length != 0 )
668                 {
669                     p_channel->psz_input_source = malloc( i_field_length + 1 );
670                     if( p_channel->psz_input_source == NULL )
671                     {
672                         intf_ErrMsg("error: %s\n", strerror( ENOMEM ));
673                         i_field = -1;
674                     }
675                     else
676                     {
677                         strcpy( p_channel->psz_input_source, psz_str );
678                     }
679                 }
680                 break;
681             case 4:                                            /* input port */
682                 p_channel->i_input_port = strtol( psz_str, &psz_end, 0);
683                 if( (*psz_str == '\0') || (*psz_end != '\0') )
684                 {
685                     i_field = -1;
686                 }
687                 break;
688             case 5:                                            /* input vlan */
689                 p_channel->i_channel = strtol( psz_str, &psz_end, 0);
690                 if( (*psz_str == '\0') || (*psz_end != '\0') )
691                 {
692                     i_field = -1;
693                 }
694                 break;
695                 /* ... following fields are ignored */
696             }
697
698             /* Set new beginning of field */
699             psz_str = psz_index + 1;
700         }
701     }
702
703     /* At least the first three fields must be parsed sucessfully for function
704      * success. Other parsing errors are returned using i_field = -1. */
705     if( i_field < 3 )
706     {
707         /* Function fails. Free allocated strings */
708         if( p_channel->psz_description != NULL )
709         {
710             free( p_channel->psz_description );
711         }
712         if( p_channel->psz_input_source != NULL )
713         {
714             free( p_channel->psz_input_source );
715         }
716         return( 1 );
717     }
718
719     /* Return success */
720     return( 0 );
721 }