905 lines
22 KiB
C
905 lines
22 KiB
C
/*
|
|
* Humax EPG Tool
|
|
* by af123, 2011
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
#include <sys/stat.h>
|
|
#ifdef HAVE_SQLITE3
|
|
#include <sqlite3.h>
|
|
#endif
|
|
#include <time.h>
|
|
#include "lint.h"
|
|
|
|
int debug = 0;
|
|
const char *version = "1.0.8";
|
|
unsigned long sysopts = 0;
|
|
unsigned long filterflags = 0;
|
|
static time_t latest_stamp = 0;
|
|
|
|
#ifdef HAVE_SQLITE3
|
|
sqlite3 *db;
|
|
sqlite3_stmt *stmt;
|
|
#endif
|
|
|
|
int
|
|
syntax()
|
|
{
|
|
fprintf(stderr, "Humax EPG Tool v%s, by af123, 2011.\n\n", version);
|
|
fprintf(stderr,
|
|
"Syntax: epg [options] [filters] <command>...\n\n");
|
|
fprintf(stderr,
|
|
" Options:\n"
|
|
" -b Brief output.\n"
|
|
" -d[level] Set debug level.\n"
|
|
" -f<file> Specify alternate EPG data file.\n"
|
|
" -h Show help text.\n"
|
|
" -p Parsable output.\n"
|
|
"\n"
|
|
);
|
|
fprintf(stderr,
|
|
" Filters: (can be specified multiple times, all must be true)\n"
|
|
" -C<CRID> Show only events with this CRID.\n"
|
|
" -D<descriptor type> Show only selected descriptor type.\n"
|
|
" -E<event id> Show only selected event.\n"
|
|
" -R<SCRID> Show only events with this Series ID.\n"
|
|
" -S<service id> Show only selected service.\n"
|
|
);
|
|
fprintf(stderr,
|
|
" -T<content type> Show only selected content types.\n"
|
|
" -@<unix timestamp> Show only programmes at time.\n"
|
|
" -/<unix timestamp> Show only programmes on day.\n"
|
|
" -/<days> Show only programmes on day.\n"
|
|
" -=<start>:<end> Show only programmes in time period.\n"
|
|
"\n"
|
|
);
|
|
fprintf(stderr,
|
|
" Commands:\n"
|
|
" dump Show a parsed summary of the EPG.\n"
|
|
" dumpraw Show raw data from the EPG.\n"
|
|
" sqldump Produce SQL statements from EPG data.\n"
|
|
#ifdef HAVE_SQLITE3
|
|
" sqlitedump <file> Create SQLite database from EPG data.\n"
|
|
#endif
|
|
);
|
|
fprintf(stderr,
|
|
" now Show what is currently on.\n"
|
|
" first Show the time of the earliest record.\n"
|
|
" last Show the time of the latest record.\n"
|
|
" parse Parse the EPG, no output.\n"
|
|
" search <text> Search programme names for text.\n"
|
|
" searchall <text> "
|
|
"Search programme names/descriptions for text.\n"
|
|
);
|
|
fprintf(stderr, "\n");
|
|
return 0;
|
|
}
|
|
|
|
#define DECOMPRESS(str, len) \
|
|
if (*(str) == 0x1f) uncompress_epg(&(str), &(len))
|
|
|
|
void
|
|
pass(struct epg *epg __attribute__((unused)),
|
|
struct section *s __attribute__((unused)),
|
|
struct data *d __attribute__((unused)),
|
|
struct descriptor **ds __attribute__((unused)),
|
|
void *var __attribute__((unused)))
|
|
{
|
|
/* Do nothing. */
|
|
}
|
|
|
|
void
|
|
latest(struct epg *epg __attribute__((unused)),
|
|
struct section *s __attribute__((unused)),
|
|
struct data *d __attribute__((unused)),
|
|
struct descriptor **ds __attribute__((unused)),
|
|
void *var __attribute__((unused)))
|
|
{
|
|
time_t tm;
|
|
|
|
tm = mjd(d->start_date, d->start_hour, d->start_min, d->start_sec);
|
|
|
|
if (tm > latest_stamp)
|
|
latest_stamp = tm;
|
|
}
|
|
|
|
void
|
|
earliest(struct epg *epg __attribute__((unused)),
|
|
struct section *s __attribute__((unused)),
|
|
struct data *d __attribute__((unused)),
|
|
struct descriptor **ds __attribute__((unused)),
|
|
void *var __attribute__((unused)))
|
|
{
|
|
time_t tm;
|
|
|
|
tm = mjd(d->start_date, d->start_hour, d->start_min, d->start_sec);
|
|
|
|
if (!latest_stamp || tm < latest_stamp)
|
|
latest_stamp = tm;
|
|
}
|
|
|
|
void
|
|
dumpraw(struct epg *epg __attribute__((unused)),
|
|
struct section *s, struct data *d, struct descriptor **ds,
|
|
void *var __attribute__((unused)))
|
|
{
|
|
dump_section(s);
|
|
dump_data(d);
|
|
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
dump_descriptor(ds[PARSER_SHORT_EVENT], 1);
|
|
if (ds[PARSER_USER_DEFINED])
|
|
dump_descriptor(ds[PARSER_USER_DEFINED], 1);
|
|
if (ds[PARSER_CONTENT])
|
|
dump_descriptor(ds[PARSER_CONTENT], 1);
|
|
if (ds[PARSER_CRID_EVENT])
|
|
dump_descriptor(ds[PARSER_CRID_EVENT], 1);
|
|
if (ds[PARSER_CRID_SERIES])
|
|
dump_descriptor(ds[PARSER_CRID_SERIES], 1);
|
|
if (ds[PARSER_CRID_REC])
|
|
dump_descriptor(ds[PARSER_CRID_REC], 1);
|
|
}
|
|
|
|
/* Strings should all be safe now the huffman module is in place... */
|
|
#define safeprintf printf
|
|
|
|
static char *
|
|
sql_escape_len(unsigned int len, char *txt)
|
|
{
|
|
static char buf[0x1000];
|
|
char *p;
|
|
unsigned int i;
|
|
|
|
p = buf;
|
|
for (i = 0; i < len && *txt; i++)
|
|
{
|
|
if (*txt == '\'')
|
|
*p++ = '\\';
|
|
*p++ = *txt++;
|
|
}
|
|
*p = '\0';
|
|
|
|
return buf;
|
|
}
|
|
|
|
#ifdef HAVE_SQLITE3
|
|
|
|
#define EXEC(xx) if (sqlite3_exec(db, xx, NULL, NULL, &error) != SQLITE_OK) \
|
|
do { \
|
|
printf("Failed: %s - %s (%s)\n", xx, error, sqlite3_errmsg(db)); \
|
|
sqlite3_free(error); \
|
|
exit(0); \
|
|
} while (0)
|
|
|
|
void
|
|
sqlitedumpstart(char *file)
|
|
{
|
|
char buf[MAXPATHLEN + 1];
|
|
char *error;
|
|
|
|
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
|
|
|
|
sprintf(buf, "%s.load", file);
|
|
|
|
unlink(buf);
|
|
|
|
if (sqlite3_open_v2(buf, &db,
|
|
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK)
|
|
{
|
|
fprintf(stderr,
|
|
"Problem creating %s, %s", buf, sqlite3_errmsg(db));
|
|
exit(1);
|
|
}
|
|
|
|
EXEC("pragma journal_mode = off");
|
|
EXEC("pragma synchronous = off");
|
|
EXEC(
|
|
"create table epg ("
|
|
"[service_id] integer, [event_id] integer, "
|
|
"[start] integer, [end] integer, [duration] integer, "
|
|
"[name] text, [text] text, [warning] text, "
|
|
"[content_type] integer, [content] text, "
|
|
"[event_crid] text, [series_crid] text, [rec_crid] text)"
|
|
);
|
|
EXEC("create index tm on epg(start,end)");
|
|
EXEC("create index start on epg(start)");
|
|
|
|
if (sqlite3_prepare_v2(db,
|
|
"insert into epg values(?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
|
-1, &stmt, NULL) != SQLITE_OK)
|
|
{
|
|
fprintf(stderr,
|
|
"Problem preparing statement %s", sqlite3_errmsg(db));
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void
|
|
sqlitedumpend(char *file)
|
|
{
|
|
char buf[MAXPATHLEN + 1];
|
|
|
|
sqlite3_finalize(stmt);
|
|
sqlite3_close(db);
|
|
|
|
sprintf(buf, "%s.load", file);
|
|
/*unlink(file);*/
|
|
rename(buf, file);
|
|
}
|
|
|
|
void
|
|
sqlitedump(struct epg *epg __attribute__((unused)),
|
|
struct section *s, struct data *d, struct descriptor **ds,
|
|
void *var __attribute__((unused)))
|
|
{
|
|
time_t tm, dur;
|
|
|
|
tm = mjd(d->start_date, d->start_hour, d->start_min, d->start_sec);
|
|
dur = d->dur_hour * 3600 + d->dur_min * 60 + d->dur_sec;
|
|
|
|
sqlite3_bind_int(stmt, 1, s->service_id);
|
|
sqlite3_bind_int(stmt, 2, d->event_id);
|
|
sqlite3_bind_int(stmt, 3, tm);
|
|
sqlite3_bind_int(stmt, 4, tm + dur);
|
|
sqlite3_bind_int(stmt, 5, dur);
|
|
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d = ds[PARSER_SHORT_EVENT];
|
|
|
|
DECOMPRESS(d->content.d77.name, d->content.d77.namelen);
|
|
DECOMPRESS(d->content.d77.text, d->content.d77.textlen);
|
|
|
|
sqlite3_bind_text(stmt, 6, d->content.d77.name, -1, NULL);
|
|
sqlite3_bind_text(stmt, 7, d->content.d77.text, -1, NULL);
|
|
}
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d = ds[PARSER_USER_DEFINED];
|
|
DECOMPRESS(d->content.d137.warning, d->content.d137.warninglen);
|
|
|
|
sqlite3_bind_text(stmt, 8, d->content.d137.warning, -1, NULL);
|
|
}
|
|
if (ds[PARSER_CONTENT])
|
|
{
|
|
sqlite3_bind_int(stmt, 9,
|
|
ds[PARSER_CONTENT]->content.d84.level1);
|
|
sqlite3_bind_text(stmt, 10, content_type(ds[PARSER_CONTENT]),
|
|
-1, NULL);
|
|
}
|
|
|
|
if (ds[PARSER_CRID_EVENT])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_EVENT];
|
|
sqlite3_bind_text(stmt, 11, d->content.d118.crids[0].crid,
|
|
-1, NULL);
|
|
}
|
|
|
|
if (ds[PARSER_CRID_SERIES])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_SERIES];
|
|
sqlite3_bind_text(stmt, 12, d->content.d118.crids[0].crid,
|
|
-1, NULL);
|
|
}
|
|
|
|
if (ds[PARSER_CRID_REC])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_REC];
|
|
sqlite3_bind_text(stmt, 13, d->content.d118.crids[0].crid,
|
|
-1, NULL);
|
|
}
|
|
|
|
if (sqlite3_step(stmt) != SQLITE_DONE)
|
|
{
|
|
fprintf(stderr, "Statement failed, %s", sqlite3_errmsg(db));
|
|
exit(1);
|
|
}
|
|
|
|
sqlite3_reset(stmt);
|
|
sqlite3_clear_bindings(stmt);
|
|
}
|
|
|
|
#endif /* HAVE_SQLITE3 */
|
|
|
|
void
|
|
sqldumpstart()
|
|
{
|
|
printf("create table if not exists epg_load\n");
|
|
printf("(\n");
|
|
printf("service_id bigint unsigned not null default 0,\n");
|
|
printf("event_id bigint unsigned not null default 0,\n");
|
|
printf("start bigint unsigned not null,\n");
|
|
printf("end bigint unsigned not null,\n");
|
|
printf("duration bigint unsigned not null,\n");
|
|
printf("name varchar(255),\n");
|
|
printf("text varchar(255),\n");
|
|
printf("warning varchar(255),\n");
|
|
printf("content_type bigint unsigned not null,\n");
|
|
printf("content varchar(255),\n");
|
|
printf("event_crid varchar(255),\n");
|
|
printf("series_crid varchar(255),\n");
|
|
printf("rec_crid varchar(255),\n");
|
|
printf("primary key (service_id, event_id),\n");
|
|
printf("index time (start,end),\n");
|
|
printf("index start (start),\n");
|
|
printf("index event_crid (event_crid),\n");
|
|
printf("index series_crid (series_crid),\n");
|
|
printf("fulltext (name),\n");
|
|
printf("fulltext (text),\n");
|
|
printf("fulltext (name,text)\n");
|
|
printf(") engine=mysql;\n");
|
|
printf("truncate epg_load;\n");
|
|
printf("lock tables epg_load write;\n");
|
|
}
|
|
|
|
void
|
|
sqldumpend()
|
|
{
|
|
printf("unlock tables;\n");
|
|
printf("analyze table epg_load;\n");
|
|
printf("drop table if exists epg;\n");
|
|
printf("alter table epg_load rename as epg;\n");
|
|
}
|
|
|
|
void
|
|
sqldump(struct epg *epg __attribute__((unused)),
|
|
struct section *s, struct data *d, struct descriptor **ds,
|
|
void *var __attribute__((unused)))
|
|
{
|
|
time_t tm, dur;
|
|
|
|
tm = mjd(d->start_date, d->start_hour, d->start_min, d->start_sec);
|
|
dur = d->dur_hour * 3600 + d->dur_min * 60 + d->dur_sec;
|
|
|
|
printf("replace into epg_load set \n");
|
|
printf(" service_id = %d,\n", s->service_id);
|
|
printf(" event_id = %d,\n", d->event_id);
|
|
printf(" start = %ld,\n", tm);
|
|
printf(" end = %ld,\n", tm + dur);
|
|
printf(" duration = %ld", dur);
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d = ds[PARSER_SHORT_EVENT];
|
|
|
|
DECOMPRESS(d->content.d77.name, d->content.d77.namelen);
|
|
DECOMPRESS(d->content.d77.text, d->content.d77.textlen);
|
|
|
|
printf(",\n name = '%s'",
|
|
sql_escape_len(d->content.d77.namelen,
|
|
d->content.d77.name));
|
|
printf(",\n text = '%s'",
|
|
sql_escape_len(d->content.d77.textlen,
|
|
d->content.d77.text));
|
|
}
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d = ds[PARSER_USER_DEFINED];
|
|
DECOMPRESS(d->content.d137.warning, d->content.d137.warninglen);
|
|
|
|
printf(",\n warning = '%s'",
|
|
sql_escape_len(d->content.d137.warninglen,
|
|
d->content.d137.warning));
|
|
}
|
|
if (ds[PARSER_CONTENT])
|
|
{
|
|
printf(",\n content_type = %d",
|
|
ds[PARSER_CONTENT]->content.d84.level1);
|
|
printf(",\n content = '%s'", content_type(ds[PARSER_CONTENT]));
|
|
}
|
|
|
|
if (ds[PARSER_CRID_EVENT])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_EVENT];
|
|
printf(",\n event_crid = '%.*s'",
|
|
d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
|
|
if (ds[PARSER_CRID_SERIES])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_SERIES];
|
|
printf(",\n series_crid = '%.*s'",
|
|
d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
|
|
if (ds[PARSER_CRID_REC])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_REC];
|
|
printf(",\n rec_crid = '%.*s'",
|
|
d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
printf(";\n");
|
|
}
|
|
|
|
void
|
|
dump(struct epg *epg __attribute__((unused)),
|
|
struct section *s, struct data *d, struct descriptor **ds,
|
|
void *var __attribute__((unused)))
|
|
{
|
|
time_t tm;
|
|
|
|
tm = mjd(d->start_date, d->start_hour, d->start_min, d->start_sec);
|
|
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
DECOMPRESS(d77->content.d77.name, d77->content.d77.namelen);
|
|
DECOMPRESS(d77->content.d77.text, d77->content.d77.textlen);
|
|
}
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d = ds[PARSER_USER_DEFINED];
|
|
DECOMPRESS(d->content.d137.warning, d->content.d137.warninglen);
|
|
}
|
|
|
|
if (sysopts & SYSOPT_PARSABLE)
|
|
{
|
|
/* service_id, event_id, start, duration, encrypted, name, text
|
|
* warning, content code, content type,
|
|
* event CRID, series CRID, rec CRID
|
|
*/
|
|
printf("%d\t%d\t%ld\t%d\t%d\t",
|
|
s->service_id, d->event_id, tm,
|
|
d->dur_hour * 3600 + d->dur_min * 60 + d->dur_sec,
|
|
d->u1.u.free_CA_mode);
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
|
|
safeprintf("%.*s\t",
|
|
d77->content.d77.namelen, d77->content.d77.name);
|
|
safeprintf("%.*s\t",
|
|
d77->content.d77.textlen, d77->content.d77.text);
|
|
}
|
|
else
|
|
printf("\t\t");
|
|
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d137 = ds[PARSER_USER_DEFINED];
|
|
|
|
safeprintf("%.*s\t", d137->content.d137.warninglen,
|
|
d137->content.d137.warning);
|
|
}
|
|
else
|
|
printf("\t");
|
|
|
|
if (ds[PARSER_CONTENT])
|
|
{
|
|
printf("%d\t", ds[PARSER_CONTENT]->content.d84.level1);
|
|
printf("%s\t", content_type(ds[PARSER_CONTENT]));
|
|
}
|
|
else
|
|
printf("\t\t");
|
|
|
|
if (ds[PARSER_CRID_EVENT])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_EVENT];
|
|
printf("%.*s\t", d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
else
|
|
printf("\t");
|
|
|
|
if (ds[PARSER_CRID_SERIES])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_SERIES];
|
|
printf("%.*s\t", d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
else
|
|
printf("\t");
|
|
|
|
if (ds[PARSER_CRID_REC])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_REC];
|
|
printf("%.*s\t", d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
else
|
|
printf("\t");
|
|
|
|
printf("\n");
|
|
return;
|
|
}
|
|
|
|
printf("----------------------------------------------------------\n");
|
|
|
|
if (sysopts & SYSOPT_BRIEF)
|
|
{
|
|
safeprintf("%d/%d: %s+%d\n",
|
|
s->service_id, d->event_id, ctime_nl(&tm),
|
|
d->dur_hour * 3600 + d->dur_min * 60 + d->dur_sec);
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
|
|
safeprintf("Name:%.*s\n",
|
|
d77->content.d77.namelen, d77->content.d77.name);
|
|
safeprintf("Text:%.*s\n",
|
|
d77->content.d77.textlen, d77->content.d77.text);
|
|
}
|
|
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d137 = ds[PARSER_USER_DEFINED];
|
|
|
|
safeprintf("Warning:%.*s\n",
|
|
d137->content.d137.warninglen,
|
|
d137->content.d137.warning);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
printf("%30s: %d\n", "Service ID", s->service_id);
|
|
printf("%30s: %d\n", "Event ID", d->event_id);
|
|
|
|
printf("%30s: %#x %d:%02d:%02d (%s)\n", "start_date",
|
|
d->start_date, d->start_hour, d->start_min, d->start_sec,
|
|
ctime_nl(&tm));
|
|
|
|
printf("%30s: %d:%02d:%02d\n", "duration",
|
|
d->dur_hour, d->dur_min, d->dur_sec);
|
|
|
|
printf("%30s: %d\n", "encrypted", d->u1.u.free_CA_mode);
|
|
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
|
|
safeprintf("%30s: %.*s\n", "Name",
|
|
d77->content.d77.namelen, d77->content.d77.name);
|
|
safeprintf("%30s: %.*s\n", "Text",
|
|
d77->content.d77.textlen, d77->content.d77.text);
|
|
}
|
|
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d137 = ds[PARSER_USER_DEFINED];
|
|
|
|
safeprintf("%30s: %.*s\n", "Warning",
|
|
d137->content.d137.warninglen, d137->content.d137.warning);
|
|
}
|
|
|
|
if (ds[PARSER_CONTENT])
|
|
printf("%30s: %s (%d)\n", "Content Type",
|
|
content_type(ds[PARSER_CONTENT]),
|
|
ds[PARSER_CONTENT]->content.d84.level1);
|
|
|
|
if (ds[PARSER_CRID_EVENT])
|
|
printf("%30s: %.*s\n", "Event CRID",
|
|
ds[PARSER_CRID_EVENT]->content.d118.crids[0].cridlen,
|
|
ds[PARSER_CRID_EVENT]->content.d118.crids[0].crid);
|
|
|
|
if (ds[PARSER_CRID_SERIES])
|
|
printf("%30s: %.*s\n", "Series CRID",
|
|
ds[PARSER_CRID_SERIES]->content.d118.crids[0].cridlen,
|
|
ds[PARSER_CRID_SERIES]->content.d118.crids[0].crid);
|
|
|
|
if (ds[PARSER_CRID_REC])
|
|
{
|
|
struct descriptor *d118 = ds[PARSER_CRID_REC];
|
|
int i;
|
|
|
|
for (i = 0; i < d118->content.d118.i; i++)
|
|
{
|
|
struct crid *crid = &d118->content.d118.crids[i];
|
|
|
|
printf("%30s: %.*s\n", "Recommended CRID",
|
|
crid->cridlen, crid->crid);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
search(struct epg *epg __attribute__((unused)),
|
|
struct section *s, struct data *d, struct descriptor **ds,
|
|
void *var)
|
|
{
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
|
|
DECOMPRESS(d77->content.d77.name, d77->content.d77.namelen);
|
|
|
|
if (strcasestr(ds[PARSER_SHORT_EVENT]->content.d77.name,
|
|
(char *)var))
|
|
dump(epg, s, d, ds, NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
searchall(struct epg *epg __attribute__((unused)),
|
|
struct section *s, struct data *d, struct descriptor **ds,
|
|
void *var)
|
|
{
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
|
|
DECOMPRESS(d77->content.d77.name, d77->content.d77.namelen);
|
|
DECOMPRESS(d77->content.d77.text, d77->content.d77.textlen);
|
|
|
|
if (strcasestr(ds[PARSER_SHORT_EVENT]->content.d77.name,
|
|
(char *)var) ||
|
|
strcasestr(ds[PARSER_SHORT_EVENT]->content.d77.text,
|
|
(char *)var))
|
|
dump(epg, s, d, ds, NULL);
|
|
}
|
|
}
|
|
|
|
#define GETOPTOPT \
|
|
do { \
|
|
if (*++cp == '\0' && argc > 1) \
|
|
{ \
|
|
argc--, argv++; \
|
|
cp = argv[0]; \
|
|
} \
|
|
while (*cp != '\0' && isspace((int)*cp)) \
|
|
cp++; \
|
|
} while (0)
|
|
|
|
#define GETOPTINTOPT \
|
|
do { \
|
|
if (*++cp == '\0' && argc > 1 && atoi(argv[1]) > 0) \
|
|
{ \
|
|
argc--, argv++; \
|
|
cp = argv[0]; \
|
|
} \
|
|
while (*cp != '\0' && isspace((int)*cp)) \
|
|
cp++; \
|
|
} while (0)
|
|
|
|
#define GETOPT \
|
|
do { \
|
|
if (*++cp == '\0' && argc < 2) \
|
|
{ \
|
|
fprintf(stderr, \
|
|
"No argument supplied for -%c\n", opt); \
|
|
exit(1); \
|
|
} \
|
|
else if (*cp == '\0') \
|
|
{ \
|
|
argc--, argv++; \
|
|
cp = argv[0]; \
|
|
} \
|
|
while (isspace((int)*cp)) \
|
|
cp++; \
|
|
} while (0)
|
|
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
char *epgpath = DEFAULT_EPG_FILE;
|
|
struct epgfilter *filter = NULL;
|
|
char *cp;
|
|
|
|
argc--, argv++;
|
|
while (argc > 0 && *argv[0] == '-')
|
|
{
|
|
for (cp = &argv[0][1]; *cp; cp++)
|
|
{
|
|
char opt;
|
|
switch (opt = *cp)
|
|
{
|
|
case 'b':
|
|
sysopts |= SYSOPT_BRIEF;
|
|
break;
|
|
|
|
case 'd':
|
|
GETOPTINTOPT;
|
|
if (*cp == '\0')
|
|
debug = 1;
|
|
else
|
|
debug = atoi(cp);
|
|
goto nextopt;
|
|
|
|
case 'f':
|
|
GETOPT;
|
|
epgpath = strdup(cp);
|
|
goto nextopt;
|
|
|
|
case 'h':
|
|
return syntax();
|
|
|
|
case 'p':
|
|
sysopts |= SYSOPT_PARSABLE;
|
|
break;
|
|
|
|
/* Filters */
|
|
case '@':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_TIMESTAMP,
|
|
atoi(cp), 0, NULL, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case '/':
|
|
{
|
|
unsigned long dstart, dend, dat;
|
|
struct tm *tm;
|
|
|
|
GETOPT;
|
|
dat = atoi(cp);
|
|
/* If specified as number of days, then convert
|
|
* to timestamp. */
|
|
if (dat < 1000)
|
|
dat = (unsigned long)time(NULL) +
|
|
dat * 86400;
|
|
tm = localtime((time_t *)&dat);
|
|
tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
|
|
dstart = mktime(tm);
|
|
tm->tm_hour = 23;
|
|
tm->tm_min = tm->tm_sec = 59;
|
|
dend = mktime(tm);
|
|
|
|
add_epgfilter(&filter, FILTER_TIMESTAMP,
|
|
dstart, dend, NULL, FT_RANGE);
|
|
goto nextopt;
|
|
}
|
|
|
|
case '=':
|
|
{
|
|
unsigned long dstart, dend;
|
|
char *p;
|
|
|
|
GETOPT;
|
|
|
|
if (!(p = strchr(cp, ':')))
|
|
{
|
|
fprintf(stderr, "Bad argument to -=\n");
|
|
exit(1);
|
|
}
|
|
*p++ = '\0';
|
|
dstart = strtoul(cp, (char **)NULL, 10);
|
|
dend = strtoul(p, (char **)NULL, 10);
|
|
|
|
if (dstart >= dend)
|
|
{
|
|
fprintf(stderr,
|
|
"Bad time range to -=\n");
|
|
exit(1);
|
|
}
|
|
|
|
add_epgfilter(&filter, FILTER_TIMERANGE,
|
|
dstart, dend, NULL, FT_RANGE);
|
|
|
|
goto nextopt;
|
|
}
|
|
|
|
case 'C':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_CRID,
|
|
0, 0, cp, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case 'D':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_DESCRIPTOR,
|
|
atoi(cp), 0, NULL, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case 'E':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_EVENT,
|
|
atoi(cp), 0, NULL, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case 'S':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_SERVICE,
|
|
atoi(cp), 0, NULL, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case 'R':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_SCRID,
|
|
0, 0, cp, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case 'T':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_CONTENT,
|
|
atoi(cp), 0, NULL, FT_EQUAL);
|
|
goto nextopt;
|
|
}
|
|
}
|
|
nextopt:
|
|
argc--, argv++;
|
|
}
|
|
|
|
if (argc < 1)
|
|
return syntax();
|
|
|
|
if (!strcmp(argv[0], "dump"))
|
|
parse(epgpath, dump, NULL, filter);
|
|
else if (!strcmp(argv[0], "parse"))
|
|
parse(epgpath, pass, NULL, filter);
|
|
else if (!strcmp(argv[0], "last"))
|
|
{
|
|
parse(epgpath, latest, NULL, filter);
|
|
printf("%ld\n", latest_stamp);
|
|
}
|
|
else if (!strcmp(argv[0], "first"))
|
|
{
|
|
parse(epgpath, earliest, NULL, filter);
|
|
printf("%ld\n", latest_stamp);
|
|
}
|
|
else if (!strcmp(argv[0], "dumpraw"))
|
|
parse(epgpath, dumpraw, NULL, filter);
|
|
else if (!strcmp(argv[0], "sqldump"))
|
|
{
|
|
sqldumpstart();
|
|
parse(epgpath, sqldump, NULL, filter);
|
|
sqldumpend();
|
|
}
|
|
#ifdef HAVE_SQLITE3
|
|
else if (!strcmp(argv[0], "sqlitedump") && argc == 2)
|
|
{
|
|
sqlitedumpstart(argv[1]);
|
|
parse(epgpath, sqlitedump, NULL, filter);
|
|
sqlitedumpend(argv[1]);
|
|
}
|
|
else if (!strcmp(argv[0], "sqlitedumpd") && argc == 2)
|
|
{
|
|
time_t last = 0;
|
|
for (;;)
|
|
{
|
|
struct stat st;
|
|
|
|
if (stat(epgpath, &st) == -1)
|
|
{
|
|
perror("stat");
|
|
return 1;
|
|
}
|
|
|
|
printf("epgd: DB time %ld, last %ld\n",
|
|
st.st_mtime, last);
|
|
fflush(stdout);
|
|
if (st.st_mtime > last)
|
|
{
|
|
time_t tm = time(NULL);
|
|
printf("epgd: Regenerating.\n");
|
|
fflush(stdout);
|
|
sqlitedumpstart(argv[1]);
|
|
parse(epgpath, sqlitedump, NULL, filter);
|
|
sqlitedumpend(argv[1]);
|
|
printf("epgd: Done in %ld seconds.\n",
|
|
time(NULL) - tm);
|
|
fflush(stdout);
|
|
}
|
|
last = st.st_mtime;
|
|
sleep(900);
|
|
}
|
|
}
|
|
#endif
|
|
else if (!strcmp(argv[0], "now"))
|
|
{
|
|
time_t tm;
|
|
|
|
time(&tm);
|
|
add_epgfilter(&filter, FILTER_TIMESTAMP, tm, 0, NULL, FT_EQUAL);
|
|
parse(epgpath, dump, NULL, filter);
|
|
}
|
|
else if (!strcmp(argv[0], "search") && argc > 1)
|
|
parse(epgpath, search, (void *)argv[1], filter);
|
|
else if (!strcmp(argv[0], "searchall") && argc > 1)
|
|
parse(epgpath, searchall, (void *)argv[1], filter);
|
|
else
|
|
syntax();
|
|
|
|
return 0;
|
|
}
|
|
|