blob: 3a3d6fd65b24824750f1ed9701033f11036cf8e0 [file] [log] [blame]
// Copyright 2011 Google Inc. All Rights Reserved.
// Author: qianzhang@google.com (Qiann Zhang)
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <assert.h>
#include <signal.h>
#include <sys/errno.h>
#include <features.h>
#include <sys/time.h>
#include <math.h>
#include <time.h>
#include <sys/timeb.h>
#include <sys/un.h>
#include <poll.h>
#include <pthread.h>
#include <dirent.h>
#include <dlfcn.h>
#include <stdarg.h>
#include <inttypes.h>
#include "channel_buffer.h"
#define sage_log(x) _sagelog x
void _sagelog( int type, int level, const char* cstr, ... );
static const char* delimiter = " \t,;\r\n:=|'\"#";
static int is_delimiter( char ch )
{
int i;
if ( ch == 0 ) return 1;
for ( i = 0; delimiter[i]; i++ )
if ( ch == delimiter[i] ) return 1;
return 0;
}
//format name:zzz (or name=zzzz)
int get_string( char*p, const char* name, char* string, int max_len, char **next )
{
char *s, *e;
e = p;
while ( e != NULL && *e ) {
s = strstr( e, name );
if ( s == NULL )
return 0;
//is a token name
if ( ((s > p && is_delimiter(*(s-1))) || s == p ) && is_delimiter( *(s+strlen(name)) ) ) {
s += (int)strlen(name);
while( *s && ( *s == ' ' || *s == '\t' ) )
s++; //skip white space
if ( *s == '=' || *s == ':' ) {
s++;
while( *s && ( *s == ' ' || *s == '\t' ) )
s++; //skip white space
if ( *s ) {
int i=0;
while ( i++<max_len && *s && *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r')
*string++ = *s++;
*string = 0x0; //terminator
if ( next != NULL ) {
while ( *s && *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r')
s++;
*next = s;
}
return 1;
}
}
}
e = ++s;
}
return 0;
}
//format name:"zzz" (or name="zzzz")
int get_string_with_quote( char*p, const char* name, char* string, int max_len, char **next )
{
char *s, *e;
e = p;
while ( e != NULL && *e ) {
s = strstr( e, name );
if ( s == NULL ) return 0;
//is a token name
if ( ((s > p && is_delimiter(*(s-1))) || s == p ) && is_delimiter( *(s+strlen(name)) ) ) {
s += (int)strlen(name);
while( *s && ( *s == ' ' || *s == '\t' ) )
s++; //skip white space
if ( *s == '=' || *s == ':' ) {
s++;
while( *s && ( *s == ' ' || *s == '\t' ) )
s++; //skip white space
if ( *s == '\"' ) {
int i=0;
s++;
while ( i++<max_len && *s && *s != '\"' )
*string++ = *s++;
*string = 0x0; //terminator
if ( next != NULL) {
while ( *s && *s != '\"' )
s++;
*next = s+1;
}
return 1;
} else
return 0;
}
}
e = ++s;
}
return 0;
}
int get_string_token( char*p, int num, char* string, int max_len, char **next )
{
int count = 0;
char *s;
s = p;
if ( s == NULL )
return 0;
while ( *s ) {
while( *s && ( *s == ' ' || *s == '\t' || *s == '\r' || *s == '\n' ) )
s++; //skip white space
if ( *s == 0 )
break;
if ( count++ != num ) {
while( *s && !( *s == ' ' || *s == '\t' || *s == ';' || *s == ',' || *s == '\r' || *s == '\n' ) )
s++; //skip a token
} else {
if ( *s ) {
int i=0;
while ( i++<max_len && *s && !( *s == ' ' || *s == '\t' || *s == ';' || *s == ',' || *s == '\r' || *s == '\n' ) )
*string++ = *s++;
*string = 0x0; //terminator
if ( next != NULL ) {
while ( *s && !( *s == ' ' || *s == '\t' || *s == '\r' || *s == '\n' ) )
s++;
*next = s;
}
return 1;
}
}
if ( *s )
s++;
}
return 0;
}
int get_int_val( char*p, const char* name, int* val, char** next )
{
char *s, *e;
e = p;
while( e != NULL && *e ) {
s = strstr( e, name );
if ( s == NULL )
return 0;
//is a token name
if ( ( (s > p && is_delimiter(*(s-1)) ) || s == p ) && is_delimiter( *(s+strlen(name)) ) ) {
s += strlen(name);
while( *s && ( *s == ' ' || *s == '\t' ) )
s++; //skip white space
if ( *s == '=' || *s == ':' ) {
s++;
while( *s && ( *s == ' ' || *s == '\t' ) )
s++; //skip white space
if ( *s ) {
*val = atoi( s );
if (*val < 0 && *s == '-' )
s++;
while( *s >= '0' && *s <= '9')
s++;
if ( next != NULL )
*next = s;
return 1;
}
}
}
e = ++s;
}
return 0;
}
//format: name val; ext
int get_cfg_val( char* string, char* name, int max_name_lenn, int* Val, char* ext, int max_ext_len )
{
const char* delima = " \t,;\r\n";
char *token, *saved_ptr;
if ( name == NULL || ext == NULL || max_name_lenn == 0 || max_ext_len == 0 )
return 0;
name[0] = 0;
*Val = 0;
ext[0] = 0;;
token = (char*)strtok_r( string, delima, &saved_ptr );
if ( token != NULL )
strncpy( name, token, max_name_lenn );
token = (char*)strtok_r( saved_ptr, delima, &saved_ptr );
if ( token != NULL ) {
*Val = atoi( token); strncpy( ext, token, max_ext_len ); }
token = (char*)strtok_r( saved_ptr, delima, &saved_ptr );
if ( token != NULL )
strncpy( ext, token, max_ext_len );
return 1;
}
int make_channel_entry_buffer( struct channel_entry_t *ce, char *buf, int size )
{
int pos = 0;
pos += snprintf( buf+pos, size-pos, "ch:%03d state:%d ", ce->ch, ce->state );
if ( ce->ctrl_bits )
pos += snprintf( buf+pos, size-pos, "ctrl:%d ", ce->ctrl_bits );
if ( ce->ch_name[0] )
pos += snprintf( buf+pos, size-pos, "name:%s ", ce->ch_name );
if ( ce->src_ip[0] )
pos += snprintf( buf+pos, size-pos, "ip:%s port:%d ", ce->src_ip, ce->src_port);
if ( ce->epg_id[0] )
pos += snprintf( buf+pos, size-pos, "epg:%s ", ce->epg_id );
if ( ce->dev_name[0] )
pos += snprintf( buf+pos, size-pos, "dev:%s ", ce->dev_name );
if ( ce->dev_tuning[0] )
pos += snprintf( buf+pos, size-pos, "tune:%s ", ce->dev_tuning );
if ( ce->av_inf[0] )
pos += snprintf( buf+pos, size-pos, "av:\"%s\" ", ce->av_inf );
if ( ce->ch_desc[0] )
pos += snprintf( buf+pos, size-pos, "desc:%s ", ce->ch_desc );
pos += snprintf( buf+pos, size-pos, "\n" );
return pos;
}
int parse_channel_entry_t_buffer( struct channel_entry_t *ce, char* buf )
{
int item = 0;
char *p = buf;
if ( !get_int_val( p, "ch", &ce->ch, NULL ) )
ce->ch = -1;
else
if ( !get_int_val( p, "state", &ce->state, NULL ) )
ce->ch = 1;
else
item++;
if ( !get_int_val( p, "ctrl", &ce->ctrl_bits, NULL ) )
ce->ctrl_bits = 0;
else
item++;
if ( !get_string( p, "name", ce->ch_name, sizeof(ce->ch_name)-1, NULL ) )
ce->ch_name[0] = 0x0;
else
item++;
if ( !get_string( p, "desc", ce->ch_desc, sizeof(ce->ch_desc)-1, NULL ) )
ce->ch_desc[0] = 0x0;
else
item++;
if ( !get_string( p, "ip", ce->src_ip, sizeof(ce->src_ip)-1, NULL ) )
ce->src_ip[0] = 0x0;
else
item++;
if ( !get_int_val( p, "port", &ce->src_port, NULL ) )
ce->src_port = -1;
else
item++;
if ( !get_string( p, "epg", ce->epg_id, sizeof(ce->epg_id)-1, NULL ) )
ce->epg_id[0] = 0x0;
else
item++;
if ( !get_string( p, "dev", ce->dev_name, sizeof(ce->dev_name)-1, NULL ) )
ce->dev_name[0] = 0x0;
else
item++;
if ( !get_string( p, "tuning", ce->dev_tuning, sizeof(ce->dev_tuning)-1, NULL ) )
ce->dev_tuning[0] = 0x0;
else
item++;
if ( !get_string_with_quote( p, "av", ce->av_inf, sizeof(ce->av_inf)-1, NULL ) )
ce->av_inf[0] = 0x0;
else
item++;
if ( !get_string_with_quote( p, "desc", ce->ch_desc, sizeof(ce->ch_desc)-1, NULL ) )
ce->ch_desc[0] = 0x0;
else
item++;
return item;
}
struct channel_list_t* create_channel_list( int num )
{
if ( num <= 0 )
return NULL;
struct channel_list_t *cl = malloc( sizeof( struct channel_list_t));
if ( cl == NULL )
return NULL;
cl->num = num;
cl->channel_num = 0;
cl->ce = malloc( sizeof(struct channel_entry_t)*num );
if ( cl->ce == NULL ) {
free( cl );
return NULL;
}
memset( cl->ce, 0x0, sizeof(struct channel_entry_t)*num );
return cl;
}
void release_channel_list( struct channel_list_t *cl )
{
if ( cl ) {
if ( cl->ce )
free( cl->ce );
free( cl );
}
}
struct channel_list_t* join_channel_list( struct channel_list_t* cl1, struct channel_list_t* cl2 )
{
int i, n, channel_num;
if ( cl1 == NULL )
return cl2;
if ( cl2 == NULL )
return cl1;
channel_num = cl1->channel_num + cl2->channel_num;
if ( channel_num < cl1->num ) {
n = 0;
for ( i = cl1->channel_num; i<channel_num; i++ ) {
cl1->ce[i] = cl2->ce[n++];
cl1->ce[i].ch = i;
}
cl2->channel_num = channel_num;
release_channel_list( cl2 );
return cl1;
} else if ( channel_num < cl2->num ) {
n = 0;
for ( i = cl2->channel_num; i<channel_num; i++ ) {
cl2->ce[i] = cl1->ce[n++];
cl2->ce[i].ch = i;
}
cl2->channel_num = channel_num;
release_channel_list( cl1 );
return cl2;
} else {
struct channel_list_t* cl = create_channel_list( channel_num );
for ( i = 0; i<cl1->channel_num; i++ ) {
cl->ce[i] = cl1->ce[i];
cl->ce[i].ch = i;
}
for ( n = 0; n<cl2->channel_num; n++, i++ ) {
cl->ce[i] = cl2->ce[n];
cl->ce[i].ch = i;
}
release_channel_list( cl1 );
release_channel_list( cl2 );
cl->channel_num = channel_num;
return cl;
}
return NULL;
}
struct channel_list_t* load_channel_entry( char* file_name )
{
int item;
int count = 0;
char buf[2048]={0};
struct channel_list_t *cl;
FILE *fp;
fp = fopen( file_name, "r" );
if ( fp == NULL ) {
//printf( "Can't open file %s to load channel table, errno:%d\n", file_name, errno );
return NULL;
}
//count entry number
while ( !feof(fp) ) {
char* p = fgets( buf, sizeof(buf)-1, fp );
if ( p == NULL )
break;
if ( buf[0] != '#' && strlen(buf) > 4 )
count++;
}
fseek( fp, 0, SEEK_SET );
cl = create_channel_list( count );
while ( !feof(fp) && cl->channel_num < cl->num ) {
char *p = fgets( buf, sizeof(buf)-1, fp );
if ( p == NULL )
break;
//skip comments
if ( buf[0] == '#' )
continue;
item = parse_channel_entry_t_buffer( &cl->ce[cl->channel_num], buf );
if ( item > 0 ) {
cl->channel_num++;
}
}
fclose( fp );
return cl;
}
int save_channel_entry( char* file_name, struct channel_list_t *cl )
{
int i;
char buf[2048];
FILE *fp;
if ( cl == NULL || cl->channel_num == 0 )
return 0;
fp = fopen( file_name, "w" );
if ( fp == NULL ) {
//printf( "Can't open file %s to save channel table, errno:%d\n", file_name, errno );
return -1;
}
fputs( "#Google sagetv channel table ver 1.0., maxium 2048 bytes per line\n", fp );
fprintf( fp, "total_channel:%d\n", cl->channel_num );
for ( i = 0; i<cl->channel_num; i++ ) {
make_channel_entry_buffer( &cl->ce[i], buf, sizeof(buf) );
fputs( buf, fp );
}
fclose( fp );
return 1;
}
char* join_alloc_string( char* str1, char* str2 )
{
int len, len1, len2;
char* str;
if ( str1 == NULL )
return str2;
if ( str2 == NULL )
return str1;
len1 = strlen( str1 );
len2 = strlen( str2 );
len = len1 + len2;
str = (char*)malloc( len+1 );
strncpy( str, str1, len1 );
strncpy( str+len1, str2, len2 );
str[len] = 0x0;
free( str1 );
free( str2 );
return str;
}