/*
* SI table generator (EN 300468)
* Copyright (C) 2004,2005 Oskar Schirmer (schirmer@scara.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Module: SI table generator
* Purpose: From a list of descriptive files generate SI tables and feed
* them to stdout.
* known bug: missing check for section length <= 1021
*/
//#define DEBUG
#include <limits.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/poll.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include "crc32.h"
#ifdef PATH_MAX
#define MY_PATH_MAX PATH_MAX
#else
#define MY_PATH_MAX 4096
#endif
static struct pollfd *pfd = NULL;
static int npfd = 0;
static int ipfd;
#define TABLE_PID_FIRST 0x10
#define TABLE_PID_LAST 0x1F
#define TABBUF_SIZE (1<<15)
#define MAX_PSI_SIZE (4096+1)
static unsigned int tabin[TABLE_PID_LAST-TABLE_PID_FIRST+1];
static unsigned int tabinold[TABLE_PID_LAST-TABLE_PID_FIRST+1];
static unsigned int tabout[TABLE_PID_LAST-TABLE_PID_FIRST+1];
static unsigned char conticnt[TABLE_PID_LAST-TABLE_PID_FIRST+1];
static unsigned char *tabbuf[TABLE_PID_LAST-TABLE_PID_FIRST+1];
#define TABLEID_FIRST 0x40
#define TABLEID_LAST 0x7F
static unsigned char nextversion[TABLEID_LAST-TABLEID_FIRST+1];
#define TS_PACKET_SIZE 188
#define TS_HEADSLEN 3
#define TS_PACKET_HEADSIZE 4
#define TS_PFIELDLEN 1
#define TS_SYNC_BYTE 0x47
#define OUTBUF_PACKETS 256
#define OUTBUF_SIZE (TS_PACKET_SIZE*OUTBUF_PACKETS)
static unsigned int outin = 0;
static unsigned int outout = 0;
static unsigned char outbuf[OUTBUF_SIZE];
static void pollfd_init()
{
ipfd = 0;
}
static int pollfd_add(int f, short e)
{
if (npfd <= ipfd) {
npfd = 2*npfd+1;
pfd = realloc(pfd, npfd * sizeof(struct pollfd));
}
pfd[ipfd].fd = f;
pfd[ipfd].events = e;
return ipfd++;
}
static int pollfd_poll(int timeout)
{
return poll(pfd, ipfd, timeout);
}
static int pollfd_rev(int i)
{
return pfd[i].revents;
}
static void signalhandler(int sig)
{
exit(0);
}
static void system_init()
{
signal(SIGINT, (void *) (*signalhandler));
signal(SIGPIPE, SIG_IGN);
}
static void unblockf(int f)
{
int r;
r = fcntl(f, F_GETFL);
if (r >= 0) {
r = fcntl(f, F_SETFL, r | O_NONBLOCK);
}
if (r < 0) {
fprintf(stderr, "fcntl failed(%d): %d\n", errno, f);
}
}
enum enumsi {
#define ENDEF_BEGIN(name,pid,tableid) name ,
#define ENDEF_END
#define ENDEF_NUMBER0(name)
#define ENDEF_NUMBER1(name)
#define ENDEF_DESCR
#define ENDEF_DATETIME
#define ENDEF_LOOP
#define ENDEF_LOOPEND0
#include "en300468ts.table"
#undef ENDEF_BEGIN
#undef ENDEF_END
#undef ENDEF_NUMBER0
#undef ENDEF_NUMBER1
#undef ENDEF_DESCR
#undef ENDEF_DATETIME
#undef ENDEF_LOOP
#undef ENDEF_LOOPEND0
num_si,
si_none = -1
};
#define DESCR_FIRST 0x40
#define DESCR_LAST 0x6E
#define PMT_POSS 0
static unsigned char descrcnt[DESCR_LAST-DESCR_FIRST+1];
const static unsigned char possible_descr[DESCR_LAST-DESCR_FIRST+1] = {
(1<<nit),
(1<<nit) | (1<<bat),
0 /* (1<<nit) | (1<<bat) | (1<<sdt) | (1<<eit) | (1<<sit) */,
(1<<nit),
(1<<nit),
PMT_POSS,
PMT_POSS,
(1<<bat) | (1<<sdt) | (1<<sit),
(1<<sdt) | (1<<sit),
(1<<bat) | (1<<sdt) | (1<<sit),
(1<<nit) | (1<<bat) | (1<<sdt) | (1<<eit) | (1<<sit),
(1<<sdt) | (1<<sit),
(1<<sdt) | (1<<sit),
(1<<eit) | (1<<sit),
(1<<eit) | (1<<sit),
(1<<eit) | (1<<sit),
(1<<eit) | (1<<sit),
(1<<sdt) | PMT_POSS | (1<<sit),
PMT_POSS,
(1<<bat) | (1<<sdt) | (1<<eit) | (1<<sit),
(1<<eit) | (1<<sit),
(1<<eit) | (1<<sit),
PMT_POSS,
(1<<sdt) | (1<<eit) | (1<<sit),
(1<<tot),
PMT_POSS,
(1<<nit),
(1<<nit),
(1<<bat),
(1<<sdt) | (1<<sit),
(1<<eit) | (1<<sit),
(1<<nit) | (1<<bat) | (1<<sdt) | (1<<eit) | PMT_POSS | (1<<sit),
PMT_POSS,
(1<<eit) | (1<<sit),
(1<<nit),
(1<<sit),
(1<<sdt) | (1<<eit) | (1<<sit),
PMT_POSS,
PMT_POSS,
0,
0,
(1<<eit),
PMT_POSS,
PMT_POSS,
(1<<nit),
(1<<nit),
(1<<nit)
};
#define LOOP_DEPTH 4
#define REALLOC_CHUNK 32
struct sitab {
struct sitab *next;
char typ;
unsigned char version;
unsigned char tableid;
long pid;
long freqmsec;
enum enumsi esi;
unsigned long *tab;
union {
struct {
int tablen;
int itab;
int fd;
int isdescr; /* 0: main table, >0: descr loop depth */
int descrtag;
int isyn;
int isyntab;
int numcount;
int loopbegin[LOOP_DEPTH];
int loopcount[LOOP_DEPTH];
int ibuf;
char buf[256];
} a;
struct {
struct timeval next;
} s;
} u;
unsigned char descrnum[DESCR_LAST-DESCR_FIRST+1];
};
static struct sitab *newtab = NULL;
static struct sitab *runtab = NULL;
#define SYNTAX_END 0
#define SYNTAX_LOOPEND 1
#define SYNTAX_LOOP 2
#define SYNTAX_DESCR 3
#define SYNTAX_DESCRTAG 4
#define SYNTAX_DATETIME 5
#define SYNTAX_STRING 6
#define SYNTAX_NUMBER -1
#define ENDEF_BEGIN(name,tag) \
const static signed char syntax_##name [] = {SYNTAX_DESCRTAG,
#define ENDEF_END SYNTAX_END};
#define ENDEF_NUMBER0(name) SYNTAX_NUMBER
#define ENDEF_NUMBER1(name) SYNTAX_NUMBER,
#define ENDEF_DATETIME SYNTAX_DATETIME,
#define ENDEF_LOOP SYNTAX_LOOP,
#define ENDEF_LOOPEND0
#define ENDEF_LOOPEND1 SYNTAX_LOOPEND,
#define ENDEF_STRING(name) SYNTAX_STRING,
#define ENDEF_STRING3(name) SYNTAX_STRING,
#include "en300468ts.descr"
#undef ENDEF_BEGIN
#undef ENDEF_END
#undef ENDEF_NUMBER0
#undef ENDEF_NUMBER1
#undef ENDEF_DATETIME
#undef ENDEF_LOOP
#undef ENDEF_LOOPEND0
#undef ENDEF_LOOPEND1
#undef ENDEF_STRING
#undef ENDEF_STRING3
static unsigned char *gen_network_name(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
i = *t++;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
*tt = t;
return d;
}
static unsigned char *gen_service_list(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
i = *t++;
while (i > 0) {
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t++;
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_satellite_delivery_system(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
unsigned char c;
*d++ = *t >> 24;
*d++ = *t >> 16;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
c = *t++ << 7;
c |= (*t++ & 0x03) << 5;
*d++ = c | (*t++ & 0x1F);
*d++ = *t >> 20;
*d++ = *t >> 12;
*d++ = *t >> 4;
c = *t++ << 4;
*d++ = c | (*t++ & 0x0F);
*tt = t;
return d;
}
static unsigned char *gen_cable_delivery_system(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
unsigned char c;
*d++ = *t >> 24;
*d++ = *t >> 16;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = 0xFF;
*d++ = 0xF0 | *t++;
*d++ = *t++;
*d++ = *t >> 20;
*d++ = *t >> 12;
*d++ = *t >> 4;
c = *t++ << 4;
*d++ = c | (*t++ & 0x0F);
*tt = t;
return d;
}
static unsigned char *gen_bouquet_name(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
i = *t++;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
*tt = t;
return d;
}
static unsigned char *gen_service(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
*d++ = *t++;
*d++ = i = *t++;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
*d++ = i = *t++;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
*tt = t;
return d;
}
static unsigned char *gen_country_availability(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i, j;
*d++ = (*t++ << 7) | 0x7F;
i = *t++;
while (i > 0) {
j = *t++;
memcpy(d, t, 3);
d += 3;
t += (j + sizeof(long) - 1) / sizeof(long);
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_linkage(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
unsigned char l, h, o;
unsigned long n, s;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = l = *t++;
h = *t++ & 0x0F;
o = *t++ & 0x01;
n = *t++;
s = *t++;
if (l == 8) {
*d++ = (h << 4) | 0x0E | o;
if ((h >= 1) && (h <= 3)) {
*d++ = n >> 8;
*d++ = n;
}
if (o == 0) {
*d++ = s >> 8;
*d++ = s;
}
}
i = *t++;
while (i > 0) {
*d++ = *t++;
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_nvod_reference(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
i = *t++;
while (i > 0) {
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_time_shifted_service(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
*d++ = *t >> 8;
*d++ = *t++;
*tt = t;
return d;
}
static unsigned char *gen_short_event(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
i = *t++;
memcpy(d, t, 3);
d += 3;
t += (i + sizeof(long) - 1) / sizeof(long);
*d++ = i = *t++;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
*d++ = i = *t++;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
*tt = t;
return d;
}
static unsigned char *gen_extended_event(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i, j;
*d++ = (descrcnt[0x4E - DESCR_FIRST] << 4)
| (st->descrnum[0x4E - DESCR_FIRST] & 0x0F);
i = *t++;
memcpy(d, t, 3);
d += 4;
t += (i + sizeof(long) - 1) / sizeof(long);
i = *t++;
while (i > 0) {
*d++ = j = *t++;
memcpy(d, t, j);
d += j;
t += (j + sizeof(long) - 1) / sizeof(long);
*d++ = j = *t++;
memcpy(d, t, j);
d += j;
t += (j + sizeof(long) - 1) / sizeof(long);
i -= 1;
}
p[4] = d-p-5;
*d++ = i = *t++;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
*tt = t;
return d;
}
static unsigned char *gen_time_shifted_event(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
*tt = t;
return d;
}
static unsigned char *gen_component(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
*d++ = 0xF0 | *t++;
*d++ = *t++;
*d++ = *t++;
i = *t++;
memcpy(d, t, 3);
d += 3;
t += (i + sizeof(long) - 1) / sizeof(long);
i = *t++;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
*tt = t;
return d;
}
static unsigned char *gen_mosaic(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
unsigned char *e;
unsigned char c;
int i, j;
c = *t++ << 7;
c = c | ((*t++ & 0x07) << 4);
*d++ = c | 0x08 | (*t++ & 0x07);
i = *t++;
while (i > 0) {
*d++ = (*t++ << 2) | 0x03;
*d++ = 0xF8 | *t++;
e = d++;
j = *t++;
while (j > 0) {
*d++ = 0xC0 | *t++;
j -= 1;
}
*e = d-e-1;
switch (*d++ = *t++) {
case 0x01:
*d++ = t[0] >> 8;
*d++ = t[0];
break;
case 0x02:
case 0x03:
*d++ = t[1] >> 8;
*d++ = t[1];
*d++ = t[2] >> 8;
*d++ = t[2];
*d++ = t[3] >> 8;
*d++ = t[3];
break;
case 0x04:
*d++ = t[1] >> 8;
*d++ = t[1];
*d++ = t[2] >> 8;
*d++ = t[2];
*d++ = t[3] >> 8;
*d++ = t[3];
*d++ = t[4] >> 8;
*d++ = t[4];
break;
}
t += 5;
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_ca_identifier(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
i = *t++;
while (i > 0) {
*d++ = *t >> 8;
*d++ = *t++;
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_content(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
i = *t++;
while (i > 0) {
*d++ = *t++;
*d++ = *t++;
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_parental_rating(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i, j;
i = *t++;
while (i > 0) {
j = *t++;
memcpy(d, t, 3);
d += 3;
t += (j + sizeof(long) - 1) / sizeof(long);
*d++ = *t++;
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_telephone(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
unsigned char c;
int i;
c = *t++ << 5;
*d = 0xC0 | c | (*t++ & 0x1F);
d += 3;
i = *t++;
c = i << 5;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
i = *t++;
c |= (i & 0x07) << 2;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
i = *t++;
p[1] = 0x80 | c | (i & 0x03);
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
i = *t++;
c = i << 4;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
i = *t++;
p[2] = 0x80 | c | (i & 0x0F);
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
*tt = t;
return d;
}
static unsigned char *gen_local_time_offset(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
unsigned char c;
int i, j;
i = *t++;
while (i > 0) {
j = *t++;
memcpy(d, t, 3);
d += 3;
t += (j + sizeof(long) - 1) / sizeof(long);
c = *t++ << 2;
*d++ = c | 0x02 | (*t++ & 0x01);
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 16;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_terrestrial_delivery_system(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
unsigned char c;
*d++ = *t >> 24;
*d++ = *t >> 16;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = (*t++ << 5) | 0x1F;
c = *t++ << 6;
c |= (*t++ & 0x07) << 3;
*d++ = c | (*t++ & 0x07);
c = *t++ << 5;
c |= (*t++ & 0x03) << 3;
c |= (*t++ & 0x03) << 1;
*d++ = c | (*t++ & 0x01);
*d++ = 0xFF;
*d++ = 0xFF;
*d++ = 0xFF;
*d++ = 0xFF;
*tt = t;
return d;
}
static unsigned char *gen_multilingual_network_name(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i, j;
i = *t++;
while (i > 0) {
j = *t++;
memcpy(d, t, 3);
d += 3;
t += (j + sizeof(long) - 1) / sizeof(long);
*d++ = j = *t++;
memcpy(d, t, j);
d += j;
t += (j + sizeof(long) - 1) / sizeof(long);
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_multilingual_bouquet_name(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i, j;
i = *t++;
while (i > 0) {
j = *t++;
memcpy(d, t, 3);
d += 3;
t += (j + sizeof(long) - 1) / sizeof(long);
*d++ = j = *t++;
memcpy(d, t, j);
d += j;
t += (j + sizeof(long) - 1) / sizeof(long);
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_multilingual_service_name(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i, j;
i = *t++;
while (i > 0) {
j = *t++;
memcpy(d, t, 3);
d += 3;
t += (j + sizeof(long) - 1) / sizeof(long);
*d++ = j = *t++;
memcpy(d, t, j);
d += j;
t += (j + sizeof(long) - 1) / sizeof(long);
*d++ = j = *t++;
memcpy(d, t, j);
d += j;
t += (j + sizeof(long) - 1) / sizeof(long);
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_multilingual_component(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i, j;
*d++ = *t++;
i = *t++;
while (i > 0) {
j = *t++;
memcpy(d, t, 3);
d += 3;
t += (j + sizeof(long) - 1) / sizeof(long);
*d++ = j = *t++;
memcpy(d, t, j);
d += j;
t += (j + sizeof(long) - 1) / sizeof(long);
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_private_data_specifier(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
*d++ = *t >> 24;
*d++ = *t >> 16;
*d++ = *t >> 8;
*d++ = *t++;
*tt = t;
return d;
}
static unsigned char *gen_short_smoothing_buffer(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
unsigned char c;
c = *t++ << 6;
*d++ = c | (*t++ & 0x3F);
*tt = t;
return d;
}
static unsigned char *gen_frequency_list(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
*d++ = 0xFC | *t++;
i = *t++;
while (i > 0) {
*d++ = *t >> 24;
*d++ = *t >> 16;
*d++ = *t >> 8;
*d++ = *t++;
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_partial_transport_stream(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
*d++ = 0xC0 | (*t >> 16);
*d++ = *t >> 8;
*d++ = *t++;
*d++ = 0xC0 | (*t >> 16);
*d++ = *t >> 8;
*d++ = *t++;
*d++ = 0xC0 | (*t >> 8);
*d++ = *t++;
*tt = t;
return d;
}
static unsigned char *gen_data_broadcast(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t++;
*d++ = i = *t++;
while (i > 0) {
*d++ = *t++;
i -= 1;
}
i = *t++;
memcpy(d, t, 3);
d += 3;
t += (i + sizeof(long) - 1) / sizeof(long);
*d++ = i = *t++;
memcpy(d, t, i);
d += i;
t += (i + sizeof(long) - 1) / sizeof(long);
*tt = t;
return d;
}
static unsigned char *gen_pdc(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
*d++ = 0xF0 | (*t >> 16);
*d++ = *t >> 8;
*d++ = *t++;
*tt = t;
return d;
}
static unsigned char *gen_cell_list(struct sitab *st, unsigned char *p,
unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
unsigned char c;
int i, j;
i = *t++;
while (i > 0) {
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 4;
c = *t++ << 4;
*d++ = c | ((*t >> 8) & 0x0F);
*d++ = *t++;
j = *t++;
*d++ = 8 * j;
while (j > 0) {
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 4;
c = *t++ << 4;
*d++ = c | ((*t >> 8) & 0x0F);
*d++ = *t++;
j -= 1;
}
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_cell_frequency_link(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
int i, j;
i = *t++;
while (i > 0) {
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 24;
*d++ = *t >> 16;
*d++ = *t >> 8;
*d++ = *t++;
j = *t++;
*d++ = 5 * j;
while (j > 0) {
*d++ = *t++;
*d++ = *t >> 24;
*d++ = *t >> 16;
*d++ = *t >> 8;
*d++ = *t++;
j -= 1;
}
i -= 1;
}
*tt = t;
return d;
}
static unsigned char *gen_announcement_support(struct sitab *st,
unsigned char *p, unsigned long **tt)
{
unsigned char *d = p;
unsigned long *t = *tt;
unsigned char c, v;
int i;
*d++ = *t >> 8;
*d++ = *t++;
i = *t++;
while (i > 0) {
c = *t++ << 4;
v = *t++ & 0x07;
*d++ = c | 0x08 | v;
switch (v) {
case 0x01:
case 0x02:
case 0x03:
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t >> 8;
*d++ = *t++;
*d++ = *t++;
break;
}
i -= 1;
}
*tt = t;
return d;
}
const static signed char *const descr_syntax[DESCR_LAST-DESCR_FIRST+1] = {
&syntax_network_name[0],
&syntax_service_list[0],
NULL,
&syntax_satellite_delivery_system[0],
&syntax_cable_delivery_system[0],
NULL,
NULL,
&syntax_bouquet_name[0],
&syntax_service[0],
&syntax_country_availability[0],
&syntax_linkage[0],
&syntax_nvod_reference[0],
&syntax_time_shifted_service[0],
&syntax_short_event[0],
&syntax_extended_event[0],
&syntax_time_shifted_event[0],
&syntax_component[0],
&syntax_mosaic[0],
NULL,
&syntax_ca_identifier[0],
&syntax_content[0],
&syntax_parental_rating[0],
NULL,
&syntax_telephone[0],
&syntax_local_time_offset[0],
NULL,
&syntax_terrestrial_delivery_system[0],
&syntax_multilingual_network_name[0],
&syntax_multilingual_bouquet_name[0],
&syntax_multilingual_service_name[0],
&syntax_multilingual_component[0],
&syntax_private_data_specifier[0],
NULL,
&syntax_short_smoothing_buffer[0],
&syntax_frequency_list[0],
&syntax_partial_transport_stream[0],
&syntax_data_broadcast[0],
NULL,
NULL,
NULL,
NULL,
&syntax_pdc[0],
NULL,
NULL,
&syntax_cell_list[0],
&syntax_cell_frequency_link[0],
&syntax_announcement_support[0]
};
static unsigned char *gendescr(struct sitab *st, unsigned char *p,
unsigned long **tt, unsigned char msb)
{
unsigned char *d = p+2;
unsigned long *t = *tt;
unsigned char *b;
unsigned char v;
int i;
i = *t++;
while (i > 0) {
b = d+2;
switch (*d = v = *t++) {
#define ENDEF_BEGIN(name,tag) case tag : d = gen_##name (st, b, &t); break;
#define ENDEF_END
#define ENDEF_NUMBER0(name)
#define ENDEF_NUMBER1(name)
#define ENDEF_DATETIME
#define ENDEF_LOOP
#define ENDEF_LOOPEND0
#define ENDEF_LOOPEND1
#define ENDEF_STRING(name)
#define ENDEF_STRING3(name)
#include "en300468ts.descr"
#undef ENDEF_BEGIN
#undef ENDEF_END
#undef ENDEF_NUMBER0
#undef ENDEF_NUMBER1
#undef ENDEF_DATETIME
#undef ENDEF_LOOP
#undef ENDEF_LOOPEND0
#undef ENDEF_LOOPEND1
#undef ENDEF_STRING
#undef ENDEF_STRING3
default:
fprintf(stderr, "error: descr not implemented (%02x)\n", *d);
exit(1);
}
descrcnt[v-DESCR_FIRST] += 1;
b[-1] = d-b;
i -= 1;
}
i = d-p-2;
p[0] = msb | (i >> 8);
p[1] = i;
*tt = t;
return d;
}
#define ENDEF_BEGIN(name,pid,tableid) \
const static signed char syntax_##name [] = {
#define ENDEF_END SYNTAX_END};
#define ENDEF_NUMBER0(name) SYNTAX_NUMBER
#define ENDEF_NUMBER1(name) SYNTAX_NUMBER,
#define ENDEF_DESCR SYNTAX_DESCR,
#define ENDEF_DATETIME SYNTAX_DATETIME,
#define ENDEF_LOOP SYNTAX_LOOP,
#define ENDEF_LOOPEND0
#include "en300468ts.table"
#undef ENDEF_BEGIN
#undef ENDEF_END
#undef ENDEF_NUMBER0
#undef ENDEF_NUMBER1
#undef ENDEF_DESCR
#undef ENDEF_DATETIME
#undef ENDEF_LOOP
#undef ENDEF_LOOPEND0
static int gentab_nit(struct sitab *st, unsigned char *b)
{
unsigned char *p = b;
unsigned long *t = st->tab;
unsigned char *q;
int i;
*p = st->tableid;
p += 3;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = 0xC0 | (st->version << 1) | 0x01;
*p++ = 0;
*p++ = 0;
p = gendescr(st, p, &t, 0xF0);
q = p;
p += 2;
i = *t++;
while (i > 0) {
*p++ = *t >> 8;
*p++ = *t++;
*p++ = *t >> 8;
*p++ = *t++;
p = gendescr(st, p, &t, 0xF0);
i -= 1;
}
i = p-q-2;
q[0] = 0xF0 | (i >> 8);
q[1] = i;
i = p-b+1;
b[1] = 0xF0 | (i >> 8);
b[2] = i;
crc32_calc(b, i-1, p);
return p-b+4;
}
static int gentab_sdt(struct sitab *st, unsigned char *b)
{
unsigned char *p = b;
unsigned long *t = st->tab;
int i;
unsigned char c;
*p = st->tableid;
p += 3;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = 0xC0 | (st->version << 1) | 0x01;
*p++ = 0;
*p++ = 0;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = 0xFF;
i = *t++;
while (i > 0) {
*p++ = *t >> 8;
*p++ = *t++;
c = *t++ << 1;
*p++ = 0xFC | c | (*t++ & 1);
c = *t++ << 5;
p = gendescr(st, p, &t, c);
i -= 1;
}
i = p-b+1;
b[1] = 0xF0 | (i >> 8);
b[2] = i;
crc32_calc(b, i-1, p);
return p-b+4;
}
static int gentab_bat(struct sitab *st, unsigned char *b)
{
unsigned char *p = b;
unsigned long *t = st->tab;
unsigned char *q;
int i;
*p = st->tableid;
p += 3;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = 0xC0 | (st->version << 1) | 0x01;
*p++ = 0;
*p++ = 0;
p = gendescr(st, p, &t, 0xF0);
q = p;
p += 2;
i = *t++;
while (i > 0) {
*p++ = *t >> 8;
*p++ = *t++;
*p++ = *t >> 8;
*p++ = *t++;
p = gendescr(st, p, &t, 0xF0);
i -= 1;
}
i = p-q-2;
q[0] = 0xF0 | (i >> 8);
q[1] = i;
i = p-b+1;
b[1] = 0xF0 | (i >> 8);
b[2] = i;
crc32_calc(b, i-1, p);
return p-b+4;
}
static int gentab_eit(struct sitab *st, unsigned char *b)
{
unsigned char *p = b;
unsigned long *t = st->tab;
int i;
unsigned char c;
struct sitab *gt;
*p = i = st->tableid;
p += 3;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = 0xC0 | (st->version << 1) | 0x01;
*p++ = 0;
*p++ = 0;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = 0;
gt = runtab;
while (gt != NULL) {
if ((gt->esi == eit) && (gt->tableid > i)) {
i = gt->tableid;
}
gt = gt->next;
}
*p++ = i;
i = *t++;
while (i > 0) {
*p++ = *t >> 8;
*p++ = *t++;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = *t >> 16;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = *t >> 16;
*p++ = *t >> 8;
*p++ = *t++;
c = *t++ << 5;
p = gendescr(st, p, &t, c);
i -= 1;
}
i = p-b+1;
b[1] = 0xF0 | (i >> 8);
b[2] = i;
crc32_calc(b, i-1, p);
return p-b+4;
}
static int gentab_rst(struct sitab *st, unsigned char *b)
{
unsigned char *p = b;
unsigned long *t = st->tab;
int i;
*p = st->tableid;
p += 3;
i = *t++;
while (i > 0) {
*p++ = *t >> 8;
*p++ = *t++;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = *t >> 8;
*p++ = *t++;
*p++ = 0xF8 | *t++;
i -= 1;
}
i = p-b-3;
b[1] = 0xF0 | (i >> 8);
b[2] = i;
return p-b;
}
static unsigned char *gentvdatetime(unsigned char *p, struct timeval *tv)
{
unsigned long d, s;
s = tv->tv_sec;
d = s / 86400;
s = s % 86400;
d += 40587;
*p++ = d >> 8;
*p++ = d;
d = s / 3600;
s = s % 3600;
d += (d / 10) * 6;
*p++ = d;
d = s / 60;
s = s % 60;
d += (d / 10) * 6;
*p++ = d;
s += (s / 10) * 6;
*p++ = s;
return p;
}
static int gentab_tdt(struct sitab *st, unsigned char *b, struct timeval *tv)
{
unsigned char *p = b;
*p++ = st->tableid;
*p++ = 0xF0;
*p++ = 0x05;
p = gentvdatetime(p, tv);
return p-b;
}
static int gentab_tot(struct sitab *st, unsigned char *b, struct timeval *tv)
{
unsigned char *p = b;
unsigned long *t = st->tab;
int i;
*p = st->tableid;
p += 3;
p = gentvdatetime(p, tv);
p = gendescr(st, p, &t, 0xF0);
i = p-b+1;
b[1] = 0xF0 | (i >> 8);
b[2] = i;
crc32_calc(b, i-1, p);
return p-b+4;
}
static int gentab_sit(struct sitab *st, unsigned char *b)
{
unsigned char *p = b;
unsigned long *t = st->tab;
unsigned char c;
int i;
*p = st->tableid;
p += 3;
*p++ = 0xFF;
*p++ = 0xFF;
*p++ = 0xC0 | (st->version << 1) | 0x01;
*p++ = 0;
*p++ = 0;
p = gendescr(st, p, &t, 0xF0);
i = *t++;
while (i > 0) {
*p++ = *t >> 8;
*p++ = *t++;
c = *t++ << 4;
p = gendescr(st, p, &t, 0x80 | c);
i -= 1;
}
i = p-b+1;
b[1] = 0xF0 | (i >> 8);
b[2] = i;
crc32_calc(b, i-1, p);
return p-b+4;
}
static int gentab_dit(struct sitab *st, unsigned char *b)
{
unsigned char *p = b;
unsigned long *t = st->tab;
*p++ = st->tableid;
*p++ = 0xF0;
*p++ = 0x01;
*p++ = (*t++ << 7) | 0x7F;
return p-b;
}
const static signed char *const tab_syntax[num_si] = {
#define ENDEF_BEGIN(name,pid,tableid) &syntax_##name [0],
#define ENDEF_END
#define ENDEF_NUMBER0(name)
#define ENDEF_NUMBER1(name)
#define ENDEF_DESCR
#define ENDEF_DATETIME
#define ENDEF_LOOP
#define ENDEF_LOOPEND0
#include "en300468ts.table"
#undef ENDEF_BEGIN
#undef ENDEF_END
#undef ENDEF_NUMBER0
#undef ENDEF_NUMBER1
#undef ENDEF_DESCR
#undef ENDEF_DATETIME
#undef ENDEF_LOOP
#undef ENDEF_LOOPEND0
};
const static signed char *const *const syntax[2] = {
&tab_syntax[0],
&descr_syntax[0]
};
static void gentab(struct sitab *st, struct timeval *tv)
{
int i, l;
unsigned char *b;
memset(&descrcnt[0], 0, sizeof(descrcnt));
i = st->pid - TABLE_PID_FIRST;
b = &tabbuf[i][tabin[i]];
*b++ = st->pid >> 8;
*b++ = st->pid;
switch (st->esi) {
case nit: l = gentab_nit(st, b); break;
case sdt: l = gentab_sdt(st, b); break;
case bat: l = gentab_bat(st, b); break;
case eit: l = gentab_eit(st, b); break;
case rst: l = gentab_rst(st, b); break;
case tdt: l = gentab_tdt(st, b, tv); break;
case tot: l = gentab_tot(st, b, tv); break;
case sit: l = gentab_sit(st, b); break;
case dit: l = gentab_dit(st, b); break;
default:
fprintf(stderr, "internal error (gentab, %d)\n", st->esi);
exit(1);
}
tabin[i] += l+2;
}
static enum enumsi alloctab(long pid, long tid)
{
enum enumsi e = si_none;
switch (pid) {
case 0x0010:
if ((tid == 0x40) || (tid == 0x41)) {
e = nit;
} else {
fprintf(stderr, "bad tableid: 0x%02lx (pid: 0x%04lx)\n", tid, pid);
}
break;
case 0x0011:
if ((tid == 0x42) || (tid == 0x46)) {
e = sdt;
} else if (tid == 0x4A) {
e = bat;
} else {
fprintf(stderr, "bad tableid: 0x%02lx (pid: 0x%04lx)\n", tid, pid);
}
break;
case 0x0012:
if ((tid >= 0x4E) && (tid <= 0x6F)) {
e = eit;
} else {
fprintf(stderr, "bad tableid: 0x%02lx (pid: 0x%04lx)\n", tid, pid);
}
break;
case 0x0013:
if (tid == 0x71) {
e = rst;
} else {
fprintf(stderr, "bad tableid: 0x%02lx (pid: 0x%04lx)\n", tid, pid);
}
break;
case 0x0014:
if (tid == 0x70) {
e = tdt;
} else if (tid == 0x73) {
e = tot;
} else {
fprintf(stderr, "bad tableid: 0x%02lx (pid: 0x%04lx)\n", tid, pid);
}
break;
case 0x001E:
if (tid == 0x7E) {
e = dit;
} else {
fprintf(stderr, "bad tableid: 0x%02lx (pid: 0x%04lx)\n", tid, pid);
}
break;
case 0x001F:
if (tid == 0x7F) {
e = sit;
} else {
fprintf(stderr, "bad tableid: 0x%02lx (pid: 0x%04lx)\n", tid, pid);
}
break;
default:
fprintf(stderr, "bad pid: 0x%04lx\n", pid);
break;
}
return e;
}
static struct sitab **findtab(struct sitab **pst, long pid, long tableid)
{
struct sitab *st = *pst;
while (st != NULL) {
if ((st->pid == pid) && (st->tableid == tableid)) {
return pst;
}
pst = &st->next;
st = *pst;
}
return NULL;
}
static void droptab(long pid, long tableid)
{
struct sitab **pst;
struct sitab *st;
pst = &newtab;
while ((pst = findtab(pst, pid, tableid)) != NULL) {
st = *pst;
*pst = st->next;
close(st->u.a.fd);
free(st->tab);
free(st);
}
pst = &runtab;
while ((pst = findtab(pst, pid, tableid)) != NULL) {
st = *pst;
*pst = st->next;
nextversion[st->tableid - TABLEID_FIRST] = (st->version + 1) & 0x1F;
free(st->tab);
free(st);
}
}
static void maketab(char typ, long pid, long tableid, long freqmsec, int fd)
{
struct sitab **pt;
struct sitab *t;
enum enumsi e;
e = alloctab(pid, tableid);
if (e >= 0) {
pt = findtab(&newtab, pid, tableid);
if (pt == NULL) {
pt = findtab(&runtab, pid, tableid);
} else {
t = *pt;
#ifdef DEBUG
fprintf(stderr, "close old fd: %d\n", t->u.a.fd);
#endif
close(t->u.a.fd);
}
if (pt == NULL) {
t = malloc(sizeof(struct sitab));
t->pid = pid;
t->tableid = tableid;
t->version = nextversion[tableid - TABLEID_FIRST];
} else {
t = *pt;
*pt = t->next;
free(t->tab);
t->version = (t->version + 1) & 0x1F;
}
t->typ = typ;
t->freqmsec = freqmsec;
t->esi = e;
t->tab = NULL;
memset(&t->descrnum[0], 0, sizeof(t->descrnum[0]));
memset(&t->u, 0, sizeof(t->u));
t->u.a.fd = fd;
t->next = newtab;
newtab = t;
}
}
static int tabline(char *b, int n)
{
char *e, *a, *z;
int i;
long v[3];
char c;
if ((n <= 0) || ((e = memchr(b, '\n', n)) == NULL)) {
return 0;
}
*e = 0;
if (b >= e) {
fprintf(stderr, "incomplete line: %s\n", b);
} else {
z = b+1;
i = 0;
c = toupper(*b);
switch (c) {
case '-':
do {
a = z;
v[i] = strtol(a, &z, 0);
} while ((a != z) && (++i < 2));
if (a == z) {
fprintf(stderr, "invalid line(%d): %s\n", a-b, b);
} else {
droptab(v[0], v[1]);
}
break;
case 'S':
do {
a = z;
v[i] = strtol(a, &z, 0);
} while ((a != z) && (++i < 3));
if (a == z) {
fprintf(stderr, "invalid line(%d): %s\n", a-b, b);
} else {
while (isspace(*z)) {
z += 1;
}
i = open(z, O_RDONLY | O_NONBLOCK);
if (i < 0) {
fprintf(stderr, "open failed(%d): %s\n", errno, z);
} else {
#ifdef DEBUG
fprintf(stderr, "table: %c, %ld, %ld, %ld, <%s>\n",
c, v[0], v[1], v[2], z);
#endif
maketab(c, v[0], v[1], v[2], i);
}
}
break;
}
}
return e-b+1;
}
static int taballoc(struct sitab *st, int cnt)
{
while (st->u.a.tablen < (st->u.a.itab + cnt)) {
st->u.a.tablen += REALLOC_CHUNK;
st->tab = realloc(st->tab, st->u.a.tablen * sizeof(unsigned long));
if (st->tab == NULL) {
return -ENOMEM;
}
}
return 0;
}
static long longval(char **n, int d)
{
long v;
int i;
char c;
v = 0;
for (i = 0; i < d; i++) {
c = *(*n)++;
if (!isdigit(c)) {
return -ENOMEM;
}
v = 10*v+c-'0';
}
return v;
}
static int siline(struct sitab *st, char *b, int n)
{
char *e, *a, *z;
long v;
int s, i;
s = syntax[(st->u.a.isdescr > 0) ? 1 : 0]
[(st->u.a.isdescr > 0) ? st->u.a.descrtag : st->esi][st->u.a.isyn];
if ((s == SYNTAX_END) || (s == SYNTAX_LOOPEND)) {
int lc;
#ifdef DEBUG
fprintf(stderr, "end:\n");
#endif
if ((lc = --st->u.a.loopcount[0]) <= 0) {
if (lc == 0) {
for (i = 0; i < LOOP_DEPTH-1; i++) {
st->u.a.loopbegin[i] = st->u.a.loopbegin[i+1];
st->u.a.loopcount[i] = st->u.a.loopcount[i+1];
}
st->u.a.loopcount[LOOP_DEPTH-1] = 0;
if (s == SYNTAX_LOOPEND) {
st->u.a.isyn += 1;
} else if (st->u.a.isdescr > 0) {
if (--st->u.a.isdescr == 0) {
st->u.a.isyn = st->u.a.isyntab;
}
}
return 0;
} else {
st->u.a.tablen = st->u.a.itab;
st->tab = realloc(st->tab, st->u.a.itab * sizeof(unsigned long));
return -ENOBUFS;
}
} else {
st->u.a.isyn = st->u.a.loopbegin[0];
return 0;
}
}
if ((n <= 0) || ((e = memchr(b, '\n', n)) == NULL)) {
return -EAGAIN;
}
*e = 0;
a = b;
while (isspace(*a)) {
a += 1;
}
if (taballoc(st, 1)) {
return -ENOMEM;
}
if (a != e) {
switch (s) {
default:
if (s > 0) {
fprintf(stderr, "internal syntax error\n");
exit(1);
}
if (st->u.a.numcount == 0) {
st->u.a.numcount = s;
}
v = strtoul(a, &z, 0);
if (a == z) {
return -EINVAL;
}
#ifdef DEBUG
fprintf(stderr, "number: %ld, %d..%d\n", v, a-b, z-b);
#endif
st->tab[st->u.a.itab++] = v;
if (++st->u.a.numcount == 0) {
st->u.a.isyn += 1;
}
*e = '\n';
return z-b;
case SYNTAX_LOOP:
v = strtol(a, &z, 0);
if (a == z) {
return -EINVAL;
}
#ifdef DEBUG
fprintf(stderr, "loop: %ld, %d..%d\n", v, a-b, z-b);
#endif
st->tab[st->u.a.itab++] = v;
if (v != 0) {
if (st->u.a.isdescr > 0) {
st->u.a.isdescr += 1;
}
for (i = LOOP_DEPTH-2; i >= 0; i--) {
st->u.a.loopbegin[i+1] = st->u.a.loopbegin[i];
st->u.a.loopcount[i+1] = st->u.a.loopcount[i];
}
st->u.a.loopbegin[0] = ++st->u.a.isyn;
st->u.a.loopcount[0] = v;
} else {
do {
st->u.a.isyn += 1;
s = syntax[(st->u.a.isdescr > 0) ? 1 : 0]
[(st->u.a.isdescr > 0) ? st->u.a.descrtag : st->esi]
[st->u.a.isyn];
if (s == SYNTAX_LOOP) {
v += 1;
}
} while ((s != SYNTAX_END) && ((s != SYNTAX_LOOPEND) || (--v >= 0)));
if (s == SYNTAX_LOOPEND) {
st->u.a.isyn += 1;
}
}
*e = '\n';
return z-b;
case SYNTAX_DESCR:
v = strtol(a, &z, 0);
if (a == z) {
return -EINVAL;
}
#ifdef DEBUG
fprintf(stderr, "descr: %ld, %d..%d\n", v, a-b, z-b);
#endif
st->tab[st->u.a.itab++] = v;
st->u.a.isyn += 1;
if (v != 0) {
st->u.a.isdescr = 1;
st->u.a.descrtag = 0;
for (i = LOOP_DEPTH-2; i >= 0; i--) {
st->u.a.loopbegin[i+1] = st->u.a.loopbegin[i];
st->u.a.loopcount[i+1] = st->u.a.loopcount[i];
}
st->u.a.loopbegin[0] = 0;
st->u.a.loopcount[0] = v;
st->u.a.isyntab = st->u.a.isyn;
st->u.a.isyn = 0;
}
*e = '\n';
return z-b;
case SYNTAX_DESCRTAG:
v = strtol(a, &z, 0);
if (a == z) {
return -EINVAL;
}
#ifdef DEBUG
fprintf(stderr, "descrtag: %ld, %d..%d\n", v, a-b, z-b);
#endif
st->tab[st->u.a.itab++] = v;
v -= DESCR_FIRST;
if ((v < 0) || (v > (DESCR_LAST - DESCR_FIRST))) {
return -EINVAL;
}
st->descrnum[v] += 1;
if (!((1 << st->esi) & possible_descr[v])) {
return -EINVAL;
}
st->u.a.descrtag = v;
st->u.a.isyn += 1;
*e = '\n';
return z-b;
case SYNTAX_DATETIME:
/* yyyy/mm/dd hh:mm:ss */
z = a;
i = e-z;
if (i < 19) {
return -EINVAL;
}
if (taballoc(st, 2)) {
return -ENOMEM;
}
if ((v = longval(&z, 4)) < 0) {
return v;
}
if ((v < 1582) || (*z++ != '/')) {
return -EINVAL;
}
if ((s = longval(&z, 2)) < 0) {
return s;
}
s -= 1;
if ((s < 0) || (s > 11) || (*z++ != '/')) {
return -EINVAL;
}
s -= 2;
if (s < 0) {
s += 12;
v -= 1;
}
v = (1461*v)/4 - ((v/100+1)*3)/4 + (153*s)/5;
if ((s = longval(&z, 2)) < 0) {
return s;
}
if ((s <= 0) || (s > 31)) {
return -EINVAL;
}
v += s - 678912;
st->tab[st->u.a.itab++] = v;
v = 0;
s = ' ';
for (i = 2; i >= 0; i--) {
if (*z++ != s) {
return -EINVAL;
}
s = *z++;
if (!isdigit(s)) {
return -EINVAL;
}
v = (v<<4) + (s-'0');
s = *z++;
if (!isdigit(s)) {
return -EINVAL;
}
v = (v<<4) + (s-'0');
s = ':';
}
st->tab[st->u.a.itab++] = v;
#ifdef DEBUG
fprintf(stderr, "datetime: %04lx %06lx, %d..%d\n",
st->tab[st->u.a.itab-2], v, a-b, z-b);
#endif
st->u.a.isyn += 1;
*e = '\n';
return z-b;
case SYNTAX_STRING:
if (*a++ != '"') {
return -EINVAL;
}
v = 0;
z = strchr(a, '"');
if (z == NULL) {
return -EINVAL;
}
i = v;
v += z-a;
taballoc(st, 1 + (v + sizeof(long) - 1) / sizeof(long));
memcpy(((char *)&st->tab[st->u.a.itab+1]) + i, a, z-a);
z += 1;
while (*z == '"') {
a = z;
z = strchr(a+1, '"');
if (z == NULL) {
return -EINVAL;
}
i = v;
v += z-a;
taballoc(st, 1 + (v + sizeof(long) - 1) / sizeof(long));
memcpy(((char *)&st->tab[st->u.a.itab+1]) + i, a, z-a);
z += 1;
}
st->tab[st->u.a.itab] = v;
#ifdef DEBUG
fprintf(stderr, "string: %ld, %d..%d\n", v, a-b, z-b);
#endif
st->u.a.itab += 1 + (v + sizeof(long) - 1) / sizeof(long);
st->u.a.isyn += 1;
*e = '\n';
return z-b;
}
} else {
return e-b+1;
}
}
static unsigned int tab2ts(unsigned char *t, unsigned char *conticnt)
{
unsigned int l, d;
unsigned char *i = &t[2];
unsigned char *o;
unsigned char c = *conticnt;
l = ((t[3] & 0x0F) << 8) + t[4] + TS_HEADSLEN + TS_PFIELDLEN;
d = (l-1) % (TS_PACKET_SIZE - TS_PACKET_HEADSIZE) + 1;
if (outin >= OUTBUF_SIZE) {
outin = 0;
}
#ifdef DEBUG
fprintf(stderr, "tab2ts(%02x,%02x,%02x,%02x,%02x; %2d), l=%d, d=%d, o:%d\n",
t[0], t[1], t[2], t[3], t[4], c, l, d, outin);
#endif
o = &outbuf[outin];
if (d <= (TS_PACKET_SIZE - TS_PACKET_HEADSIZE - 1)) {
if (d < (TS_PACKET_SIZE - TS_PACKET_HEADSIZE - 1)) {
o[5] = 0; /* no indicators, no flags, padding: */
memset(&o[6], -1, TS_PACKET_SIZE - TS_PACKET_HEADSIZE - 2 - d);
}
o[4] = TS_PACKET_SIZE - TS_PACKET_HEADSIZE - 1 - d;
o[3] = (0x00 << 6) | (0x03 << 4) | c;
} else {
o[3] = (0x00 << 6) | (0x01 << 4) | c;
}
o[TS_PACKET_SIZE - d] = 0; /* pointer_field */
d -= TS_PFIELDLEN;
memcpy(&o[TS_PACKET_SIZE - d], i, d);
i += d;
d = l - d - TS_PFIELDLEN;
o[1] = (0 << 7) | (1 << 6) | (0 << 5) | t[0];
o[2] = t[1];
o[0] = TS_SYNC_BYTE;
c = (c + 1) & 0x0F;
outin += TS_PACKET_SIZE;
while (d > 0) {
if (outin >= OUTBUF_SIZE) {
outin = 0;
}
o = &outbuf[outin];
o[3] = (0x00 << 6) | (0x01 << 4) | c;
memcpy(&o[4], i, TS_PACKET_SIZE-TS_PACKET_HEADSIZE);
i += (TS_PACKET_SIZE - TS_PACKET_HEADSIZE);
d -= (TS_PACKET_SIZE - TS_PACKET_HEADSIZE);
o[1] = (0 << 7) | (0 << 6) | (0 << 5) | t[0];
o[2] = t[1];
o[0] = TS_SYNC_BYTE;
c = (c + 1) & 0x0F;
outin += TS_PACKET_SIZE;
}
*conticnt = c;
return l+1;
}
static void argloop(int f0)
{
int i0 = 0;
int o0 = 0;
char buf0[PATH_MAX];
do {
int i, n, r, n0, n1, nst, tmo;
struct timeval tv;
struct sitab *st;
struct sitab **pst;
pollfd_init();
tmo = -1;
n0 = -1;
nst = -1;
if (newtab != NULL) {
nst = pollfd_add(newtab->u.a.fd, POLLIN);
} else if ((r = tabline(&buf0[o0], i0))) {
o0 += r;
i0 -= r;
tmo = 0;
} else {
if ((i0 > 0) && (o0 > 0)) {
memmove(&buf0[0], &buf0[o0], i0);
o0 = 0;
}
if (i0 == sizeof(buf0)-1) {
buf0[sizeof(buf0)-1] = '\n';
i0 += 1;
tmo = 0;
} else if (f0 >= 0) {
n0 = pollfd_add(f0, POLLIN);
}
}
if (outin == 0) {
r = OUTBUF_SIZE;
n1 = -1;
} else {
r = outout - outin;
if (r < 0) {
r += OUTBUF_SIZE;
}
n1 = pollfd_add(STDOUT_FILENO, POLLOUT);
}
i = 0;
while (tmo != 0 && i <= TABLE_PID_LAST-TABLE_PID_FIRST) {
if ((tabin[i] > tabout[i])
&& (r >= (((((tabbuf[i][tabout[i]+3] & 0x0F) << 8)
+ tabbuf[i][tabout[i]+4] + TS_HEADSLEN + TS_PFIELDLEN
+ TS_PACKET_SIZE - TS_PACKET_HEADSIZE)
* 131) / 128))) {
tmo = 0;
#ifdef DEBUG
{
int x;
fprintf(stderr, "tabbuf[%d..%d-1]:\n", tabout[i], tabin[i]);
for (x = tabout[i]; x < tabin[i]; x++) {
fprintf(stderr, "%02x ", tabbuf[i][x]);
}
fprintf(stderr, "\n");
}
#endif
}
i += 1;
}
gettimeofday(&tv, NULL);
st = runtab;
while (st != NULL) {
i = st->pid - TABLE_PID_FIRST;
if ((i < 0) || (i >= (TABLE_PID_LAST-TABLE_PID_FIRST))) {
fprintf(stderr, "internal error (pid)\n");
exit(1);
}
tabinold[i] = tabin[i];
if (tmo != 0) {
if (tabin[i] == 0) {
i = (st->u.s.next.tv_sec - tv.tv_sec) * 1000
+ (st->u.s.next.tv_usec - tv.tv_usec) / 1000;
if (i <= 0) {
tmo = 0;
} else if ((tmo < 0) || (i < tmo)) {
tmo = i;
}
}
}
st = st->next;
}
n = pollfd_poll(tmo);
gettimeofday(&tv, NULL);
for (i = 0; i <= TABLE_PID_LAST-TABLE_PID_FIRST; i++) {
while ((tabin[i] > tabout[i])
&& (r >= (((((tabbuf[i][tabout[i]+3] & 0x0F) << 8)
+ tabbuf[i][tabout[i]+4] + TS_HEADSLEN + TS_PFIELDLEN
+ TS_PACKET_SIZE - TS_PACKET_HEADSIZE)
* 131) / 128))) {
tabout[i] += tab2ts(&tabbuf[i][tabout[i]], &conticnt[i]);
r = outout - outin;
if (r < 0) {
r += OUTBUF_SIZE;
}
}
if (tabin[i] <= tabout[i]) {
tabin[i] = tabout[i] = 0;
}
}
if ((n > 0) && (n1 >= 0) && (r = pollfd_rev(n1))) {
if (r & (POLLNVAL | POLLERR)) {
fprintf(stderr, "poll error: %x\n", r);
return;
}
if (outout >= OUTBUF_SIZE) {
outout = 0;
}
r = ((outin > outout) ? outin : OUTBUF_SIZE) - outout;
r = write(STDOUT_FILENO, &outbuf[outout], r);
if (r < 0) {
fprintf(stderr, "write error(%d)\n", errno);
return;
}
if (r == 0) {
exit(0);
}
outout += r;
if (outout == outin) {
outin = outout = 0;
}
}
pst = &runtab;
while ((st = *pst) != NULL) {
i = st->pid - TABLE_PID_FIRST;
if ((tabinold[i] == 0)
&& (tabin[i] < (TABBUF_SIZE-MAX_PSI_SIZE+1-2))
&& ((st->u.s.next.tv_sec < tv.tv_sec)
|| ((st->u.s.next.tv_sec == tv.tv_sec)
&& (st->u.s.next.tv_usec <= tv.tv_usec)))) {
if (st->freqmsec > 0) {
i = (st->u.s.next.tv_sec - tv.tv_sec) * 1000
+ (st->u.s.next.tv_usec - tv.tv_usec) / 1000;
if (i < -st->freqmsec) {
st->u.s.next = tv;
} else {
st->u.s.next.tv_sec += st->freqmsec / 1000;
st->u.s.next.tv_usec += (st->freqmsec % 1000) * 1000;
if (st->u.s.next.tv_usec > 1000000) {
st->u.s.next.tv_usec -= 1000000;
st->u.s.next.tv_sec += 1;
}
}
}
#ifdef DEBUG
fprintf(stderr, "do tab: %ld.%06ld: %ld, %u\n", tv.tv_sec, tv.tv_usec,
st->pid, st->tableid);
#endif
gentab(st, &tv);
if (st->freqmsec <= 0) {
*pst = st->next;
nextversion[st->tableid - TABLEID_FIRST] = (st->version + 1) & 0x1F;
free(st->tab);
free(st);
} else {
pst = &st->next;
}
} else {
pst = &st->next;
}
}
if ((n > 0) && (nst >= 0)) {
pst = &newtab;
do {
st = *pst;
if ((r = pollfd_rev(nst))) {
if (r & (POLLNVAL | POLLERR)) {
fprintf(stderr, "poll error: %x\n", r);
*pst = st->next;
close(st->u.a.fd);
free(st->tab);
free(st);
} else {
i = st->u.a.ibuf;
r = read(st->u.a.fd, &st->u.a.buf[i], sizeof(st->u.a.buf) - i - 1);
if (r <= 0) {
fprintf(stderr, "read error(%d): %d\n", errno, st->u.a.fd);
*pst = st->next;
close(st->u.a.fd);
free(st->tab);
free(st);
} else {
int j = 0;
i += r;
while ((r = siline(st, &st->u.a.buf[j], i)) >= 0) {
j += r;
i -= r;
}
switch (r) {
case -ENOBUFS:
*pst = st->next;
close(st->u.a.fd);
#ifdef DEBUG
fprintf(stderr, "done, itab=%d\n", st->u.a.itab);
for (i = 0; i < st->u.a.itab; i++) {
fprintf(stderr, "%lu,", st->tab[i]);
}
fprintf(stderr, "\n");
#endif
i = st->pid - TABLE_PID_FIRST;
if ((tabbuf[i] == NULL)
&& ((tabbuf[i] = malloc(TABBUF_SIZE)) == NULL)) {
fprintf(stderr, "malloc failed for table buffer pid=%02lx\n",
st->pid);
free(st->tab);
free(st);
}
st->next = runtab;
runtab = st;
st->u.s.next = tv;
break;
case -EAGAIN:
if (i > 0) {
memmove(&st->u.a.buf[0], &st->u.a.buf[j], i);
}
st->u.a.ibuf = i;
pst = &st->next;
break;
default:
fprintf(stderr, "eval error: %d\n", r);
*pst = st->next;
close(st->u.a.fd);
free(st->tab);
free(st);
break;
}
}
}
n -= 1;
} else {
pst = &st->next;
}
nst += 1;
} while ((*pst != NULL) && (n > 0));
}
if ((n > 0) && (n0 >= 0) && (r = pollfd_rev(n0))) {
if (r & (POLLNVAL | POLLERR)) {
fprintf(stderr, "poll error: %x\n", r);
return;
}
r = read(f0, &buf0[i0], sizeof(buf0) - i0 - 1);
if (r < 0) {
fprintf(stderr, "read error(%d): %d\n", errno, f0);
return;
}
if (r == 0) {
return;
}
i0 += r;
n -= 1;
}
} while (1);
}
int main(int argc, char *argv[])
{
int f = -1;
int a;
if (sizeof(unsigned) != sizeof(struct loop_descr *)) {
fprintf(stderr, "data type prerequisites not met\n");
return 1;
}
gen_crc32_table();
system_init();
unblockf(STDIN_FILENO);
unblockf(STDOUT_FILENO);
memset(&tabin[0], 0, sizeof(tabin));
memset(&tabout[0], 0, sizeof(tabout));
memset(&conticnt[0], 0, sizeof(conticnt));
memset(&nextversion[0], 0, sizeof(nextversion));
for (a = TABLE_PID_LAST-TABLE_PID_FIRST; a >= 0; a--) {
tabbuf[a] = NULL;
}
a = 1;
do {
if ((a < argc) && (strcmp(argv[a], "-"))) {
f = open(argv[a], O_RDONLY | O_NONBLOCK);
if (f < 0) {
fprintf(stderr, "open failed(%d): %s\n", errno, argv[a]);
}
} else {
f = STDIN_FILENO;
}
argloop(f);
} while (++a < argc);
argloop(-1);
return 0;
}
LinuxTV legacy CVS <linuxtv.org/cvs>