]> git.sesse.net Git - vlc/blob - src/interface/interface.c
Hello,
[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           
299             if( p_cur == NULL )
300             {
301                 p_cur = (p_intf_key )(malloc ( sizeof( intf_key ) ) );
302                 p_cur->received_key = r_key;
303                 p_cur->forwarded.key = f_key;
304                 p_cur->forwarded.param = param; 
305                 p_cur->next = NULL;
306                 p_intf->p_keys = p_cur;
307             } else {
308                 while( p_cur->next != NULL && p_cur ->received_key != r_key)
309                 {
310                     p_cur = p_cur->next;
311                 }
312                 if( p_cur->next == NULL )
313                 {   
314                     p_cur->next  = ( p_intf_key )( malloc( sizeof( intf_key ) ) );
315                     p_cur = p_cur->next;
316                     p_cur->next = NULL;
317                     p_cur->forwarded.param = param; 
318                     p_cur->received_key = r_key;
319                 }
320                 p_cur->forwarded.key = f_key;
321             }        
322         }
323
324         /*****************************************************************************
325          * intf_AssignSKey: assign standartkeys                                      *
326          *****************************************************************************
327          * This function fills in the associative array that links the key pressed   *
328          * and the key we use internally.                                            *
329          ****************************************************************************/
330         void intf_AssignSKey(intf_thread_t *p_intf, int r_key, int f_key)
331         {
332             intf_AssignKey( p_intf, r_key, f_key, 0);
333         }
334
335
336         /* Basic getKey function... */
337         keyparm intf_getKey( intf_thread_t *p_intf, int r_key)
338         {   
339             keyparm reply;
340             
341             p_intf_key current = p_intf->p_keys;
342             while(current != NULL && current->received_key != r_key)
343             {    
344                 current = current->next;
345             }
346             if(current == NULL)
347             {   /* didn't find any key in the array */ 
348                 reply.key=VLC_UNKNOWN;
349                 reply.param=0;
350             }
351             else
352             {
353                 reply.key = current->forwarded.key;
354                 reply.param = current->forwarded.param;
355             }
356             return reply;
357         }
358
359         /*****************************************************************************
360          * intf_AssignNormalKeys: used for normal interfaces.
361          *****************************************************************************
362          * This function assign the basic key to the normal keys.
363          *****************************************************************************/
364
365 void intf_AssignNormalKeys( intf_thread_t *p_intf)
366         {
367             p_intf->p_intf_getKey = intf_getKey;
368
369             intf_AssignSKey( p_intf , 'Q', VLC_QUIT);
370             intf_AssignSKey( p_intf , 'q', VLC_QUIT);
371             intf_AssignSKey( p_intf ,  27, VLC_QUIT);
372             intf_AssignSKey( p_intf ,   3, VLC_QUIT);
373             intf_AssignKey( p_intf , '0', VLC_CHANNEL, 0);
374             intf_AssignKey( p_intf , '1', VLC_CHANNEL, 1);
375             intf_AssignKey( p_intf , '2', VLC_CHANNEL, 2);
376             intf_AssignKey( p_intf , '3', VLC_CHANNEL, 3);
377             intf_AssignKey( p_intf , '4', VLC_CHANNEL, 4);
378             intf_AssignKey( p_intf , '5', VLC_CHANNEL, 5);
379             intf_AssignKey( p_intf , '6', VLC_CHANNEL, 6);
380             intf_AssignKey( p_intf , '7', VLC_CHANNEL, 7);
381             intf_AssignKey( p_intf , '8', VLC_CHANNEL, 8);
382             intf_AssignKey( p_intf , '9', VLC_CHANNEL, 9);
383             intf_AssignKey( p_intf , '0', VLC_CHANNEL, 0);
384             intf_AssignSKey( p_intf , '+', VLC_LOUDER);
385             intf_AssignSKey( p_intf , '-', VLC_QUIETER);
386             intf_AssignSKey( p_intf , 'm', VLC_MUTE);
387             intf_AssignSKey( p_intf , 'M', VLC_MUTE);
388             intf_AssignSKey( p_intf , 'g', VLC_LESS_GAMMA);
389             intf_AssignSKey( p_intf , 'G', VLC_MORE_GAMMA);
390             intf_AssignSKey( p_intf , 'c', VLC_GRAYSCALE);
391             intf_AssignSKey( p_intf , ' ', VLC_INTERFACE);
392             intf_AssignSKey( p_intf , 'i', VLC_INFO);
393             intf_AssignSKey( p_intf , 's', VLC_SCALING);
394 }   
395
396 /*****************************************************************************
397  * intf_ProcessKey: process standard keys
398  *****************************************************************************
399  * This function will process standard keys and return non 0 if the key was
400  * unknown.
401  *****************************************************************************/
402 int intf_ProcessKey( intf_thread_t *p_intf, int g_key )
403 {
404     static int i_volbackup;
405     keyparm i_reply;
406     
407     i_reply = intf_getKey( p_intf, g_key); 
408     
409     switch( i_reply.key )
410     {
411     case VLC_QUIT:                                                  /* quit order */
412         p_intf->b_die = 1;
413         break;
414     case VLC_CHANNEL:
415         /* Change channel - return code is ignored since SelectChannel displays
416          * its own error messages */
417         intf_SelectChannel( p_intf, i_reply.param - '0' );
418         break;
419     case VLC_LOUDER:                                                    /* volume + */
420         if( (p_main->p_aout != NULL) && (p_main->p_aout->vol < VOLMAX) )
421             p_main->p_aout->vol += VOLSTEP;
422         break;
423     case VLC_QUIETER:                                                    /* volume - */
424         if( (p_main->p_aout != NULL) && (p_main->p_aout->vol > VOLSTEP) )
425             p_main->p_aout->vol -= VOLSTEP;
426         break;
427     case VLC_MUTE:                                                 /* toggle mute */
428         if( (p_main->p_aout != NULL) && (p_main->p_aout->vol))
429         {
430             i_volbackup = p_main->p_aout->vol;
431             p_main->p_aout->vol = 0;
432         }
433         else if( (p_main->p_aout != NULL) && (!p_main->p_aout->vol))
434             p_main->p_aout->vol = i_volbackup;
435         break;
436     case VLC_LESS_GAMMA:                                                     /* gamma - */
437         if( (p_intf->p_vout != NULL) && (p_intf->p_vout->f_gamma > -INTF_GAMMA_LIMIT) )
438         {
439             vlc_mutex_lock( &p_intf->p_vout->change_lock );
440             p_intf->p_vout->f_gamma   -= INTF_GAMMA_STEP;
441             p_intf->p_vout->i_changes |= VOUT_GAMMA_CHANGE;
442             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
443         }
444         break;
445     case VLC_MORE_GAMMA:                                                     /* gamma + */
446         if( (p_intf->p_vout != NULL) && (p_intf->p_vout->f_gamma < INTF_GAMMA_LIMIT) )
447         {
448             vlc_mutex_lock( &p_intf->p_vout->change_lock );
449             p_intf->p_vout->f_gamma   += INTF_GAMMA_STEP;
450             p_intf->p_vout->i_changes |= VOUT_GAMMA_CHANGE;
451             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
452         }
453         break;
454     case VLC_GRAYSCALE:                                            /* toggle grayscale */
455         if( p_intf->p_vout != NULL )
456         {
457             vlc_mutex_lock( &p_intf->p_vout->change_lock );
458             p_intf->p_vout->b_grayscale = !p_intf->p_vout->b_grayscale;
459             p_intf->p_vout->i_changes  |= VOUT_GRAYSCALE_CHANGE;
460             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
461         }
462         break;
463     case VLC_INTERFACE:                                            /* toggle interface */
464         if( p_intf->p_vout != NULL )
465         {
466             vlc_mutex_lock( &p_intf->p_vout->change_lock );
467             p_intf->p_vout->b_interface     = !p_intf->p_vout->b_interface;
468             p_intf->p_vout->i_changes |= VOUT_INTF_CHANGE;
469             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
470         }
471         break;
472     case VLC_INFO:                                                 /* toggle info */
473         if( p_intf->p_vout != NULL )
474         {
475             vlc_mutex_lock( &p_intf->p_vout->change_lock );
476             p_intf->p_vout->b_info     = !p_intf->p_vout->b_info;
477             p_intf->p_vout->i_changes |= VOUT_INFO_CHANGE;
478             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
479         }
480         break;
481     case VLC_SCALING:                                              /* toggle scaling */
482         if( p_intf->p_vout != NULL )
483         {
484             vlc_mutex_lock( &p_intf->p_vout->change_lock );
485             p_intf->p_vout->b_scale    = !p_intf->p_vout->b_scale;
486             p_intf->p_vout->i_changes |= VOUT_SCALE_CHANGE;
487             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
488         }
489         break;
490    default:                                                   /* unknown key */
491         return( 1 );
492     }
493
494     return( 0 );
495 }
496
497 /* following functions are local */
498
499 /*****************************************************************************
500  * LoadChannels: load channels description from a file
501  *****************************************************************************
502  * This structe describes all interface-specific data of the main (interface)
503  * thread.
504  * Each line of the file is a semicolon separated list of the following
505  * fields :
506  *      integer         channel number
507  *      string          channel description
508  *      integer         input method (see input.h)
509  *      string          input source
510  *      integer         input port
511  *      integer         input vlan
512  * The last field must end with a semicolon.
513  * Comments and empty lines are not explicitely allowed, but lines with parsing
514  * errors are ignored without warning.
515  *****************************************************************************/
516 static int LoadChannels( intf_thread_t *p_intf, char *psz_filename )
517 {
518     FILE *              p_file;                                      /* file */
519     intf_channel_t *    p_channel;                        /* current channel */
520     char                psz_line[INTF_MAX_CMD_SIZE];          /* line buffer */
521     int                 i_index;                   /* channel or field index */
522
523     /* Set default value */
524     p_intf->p_channel = NULL;
525
526     /* FIXME: channels are disabled */
527     return( 0 );
528
529     /* Open file */
530     p_file = fopen( psz_filename, "r" );
531     if( p_file == NULL )
532     {
533         intf_ErrMsg("error: can't open %s (%s)\n", psz_filename, strerror(errno));
534         return( 1 );
535     }
536
537     /* First pass: count number of lines */
538     for( i_index = 0; fgets( psz_line, INTF_MAX_CMD_SIZE, p_file ) != NULL; i_index++ )
539     {
540         ;
541     }
542
543     if( i_index != 0 )
544     {
545         /* Allocate array and rewind - some of the lines may be invalid, and the
546          * array will probably be larger than the actual number of channels, but
547          * it has no consequence. */
548         p_intf->p_channel = malloc( sizeof( intf_channel_t ) * i_index );
549         if( p_intf->p_channel == NULL )
550         {
551             intf_ErrMsg("error: %s\n", strerror(ENOMEM));
552             fclose( p_file );
553             return( 1 );
554         }
555         p_channel = p_intf->p_channel;
556         rewind( p_file );
557
558         /* Second pass: read channels descriptions */
559         while( fgets( psz_line, INTF_MAX_CMD_SIZE, p_file ) != NULL )
560         {
561             if( !ParseChannel( p_channel, psz_line ) )
562             {
563                 intf_DbgMsg( "channel [%d] %s : method %d (%s:%d vlan %d)\n",
564                          p_channel->i_channel, p_channel->psz_description,
565                          p_channel->i_input_method,
566                          p_channel->psz_input_source,
567                          p_channel->i_input_port, p_channel->i_input_vlan );
568                 p_channel++;
569             }
570         }
571
572         /* Add marker at the end of the array */
573         p_channel->i_channel = -1;
574     }
575
576     /* Close file */
577     fclose( p_file );
578     return( 0 );
579 }
580
581 /*****************************************************************************
582  * UnloadChannels: unload channels description
583  *****************************************************************************
584  * This function free all resources allocated by LoadChannels, if any.
585  *****************************************************************************/
586 static void UnloadChannels( intf_thread_t *p_intf )
587 {
588     int i_channel;                                          /* channel index */
589
590     if( p_intf->p_channel != NULL )
591     {
592         /* Free allocated strings */
593         for( i_channel = 0;
594              p_intf->p_channel[ i_channel ].i_channel != -1;
595              i_channel++ )
596         {
597             if( p_intf->p_channel[ i_channel ].psz_description != NULL )
598             {
599                 free( p_intf->p_channel[ i_channel ].psz_description );
600             }
601             if( p_intf->p_channel[ i_channel ].psz_input_source != NULL )
602             {
603                 free( p_intf->p_channel[ i_channel ].psz_input_source );
604             }
605         }
606
607         /* Free array */
608         free( p_intf->p_channel );
609         p_intf->p_channel = NULL;
610     }
611 }
612
613
614 /*****************************************************************************
615  * ParseChannel: parse a channel description line
616  *****************************************************************************
617  * See LoadChannels. This function return non 0 on parsing error.
618  *****************************************************************************/
619 static int ParseChannel( intf_channel_t *p_channel, char *psz_str )
620 {
621     char *      psz_index;                              /* current character */
622     char *      psz_end;                           /* end pointer for strtol */
623     int         i_field;                        /* field number, -1 on error */
624     int         i_field_length;             /* field length, for text fields */
625
626     /* Set some default fields */
627     p_channel->i_channel =              0;
628     p_channel->psz_description =        NULL;
629     p_channel->i_input_method =         0;
630     p_channel->psz_input_source =       NULL;
631     p_channel->i_input_port =           0;
632     p_channel->i_input_vlan =           0;
633
634     /* Parse string */
635     i_field = 0;
636     for( psz_index = psz_str; (i_field != -1) && (*psz_index != '\0'); psz_index++ )
637     {
638         if( *psz_index == ';' )
639         {
640             /* Mark end of field */
641             *psz_index = '\0';
642
643             /* Parse field */
644             switch( i_field++ )
645             {
646             case 0:                                        /* channel number */
647                 p_channel->i_channel = strtol( psz_str, &psz_end, 0);
648                 if( (*psz_str == '\0') || (*psz_end != '\0') )
649                 {
650                     i_field = -1;
651                 }
652                 break;
653             case 1:                                   /* channel description */
654                 i_field_length = strlen( psz_str );
655                 if( i_field_length != 0 )
656                 {
657                     p_channel->psz_description = malloc( i_field_length + 1 );
658                     if( p_channel->psz_description == NULL )
659                     {
660                         intf_ErrMsg("error: %s\n", strerror( ENOMEM ));
661                         i_field = -1;
662                     }
663                     else
664                     {
665                         strcpy( p_channel->psz_description, psz_str );
666                     }
667                 }
668                 break;
669             case 2:                                          /* input method */
670                 p_channel->i_input_method = strtol( psz_str, &psz_end, 0);
671                 if( (*psz_str == '\0') || (*psz_end != '\0') )
672                 {
673                     i_field = -1;
674                 }
675                 break;
676             case 3:                                          /* input source */
677                 i_field_length = strlen( psz_str );
678                 if( i_field_length != 0 )
679                 {
680                     p_channel->psz_input_source = malloc( i_field_length + 1 );
681                     if( p_channel->psz_input_source == NULL )
682                     {
683                         intf_ErrMsg("error: %s\n", strerror( ENOMEM ));
684                         i_field = -1;
685                     }
686                     else
687                     {
688                         strcpy( p_channel->psz_input_source, psz_str );
689                     }
690                 }
691                 break;
692             case 4:                                            /* input port */
693                 p_channel->i_input_port = strtol( psz_str, &psz_end, 0);
694                 if( (*psz_str == '\0') || (*psz_end != '\0') )
695                 {
696                     i_field = -1;
697                 }
698                 break;
699             case 5:                                            /* input vlan */
700                 p_channel->i_channel = strtol( psz_str, &psz_end, 0);
701                 if( (*psz_str == '\0') || (*psz_end != '\0') )
702                 {
703                     i_field = -1;
704                 }
705                 break;
706                 /* ... following fields are ignored */
707             }
708
709             /* Set new beginning of field */
710             psz_str = psz_index + 1;
711         }
712     }
713
714     /* At least the first three fields must be parsed sucessfully for function
715      * success. Other parsing errors are returned using i_field = -1. */
716     if( i_field < 3 )
717     {
718         /* Function fails. Free allocated strings */
719         if( p_channel->psz_description != NULL )
720         {
721             free( p_channel->psz_description );
722         }
723         if( p_channel->psz_input_source != NULL )
724         {
725             free( p_channel->psz_input_source );
726         }
727         return( 1 );
728     }
729
730     /* Return success */
731     return( 0 );
732 }