blob: 0a8ded076d7841a265da20a5f9c69a25c280048a [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"
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., maximum 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;
}