All of lore.kernel.org
 help / color / mirror / Atom feed
* [Patch] New utility program atsc_epg added to dvb-apps utility suite.
@ 2009-06-17 23:18 Yufei Yuan
  2009-06-17 23:51 ` hermann pitton
  2009-06-18  8:32 ` Manu Abraham
  0 siblings, 2 replies; 22+ messages in thread
From: Yufei Yuan @ 2009-06-17 23:18 UTC (permalink / raw)
  To: Linux Media Mailing List

[-- Attachment #1: Type: text/plain, Size: 668 bytes --]

Hi,

I am not sure if this is the correct mailing list to send this patch.
>From the LinuxTV website, it seems that currently dvb-apps project has
no owner.

A new utility atsc_epg is added into the dvb-apps utility suite. It
parses PSIP information carried in OTA ATSC channels, and constructs a
basic EPG in a terminal window. Changes were also made to files to
please GCC4.4.

The patch is against latest revision 1278 from the dvb-apps repository.

Regards,
Yufei Yuan

-- 
好学近乎智,力行近乎仁,知耻近乎勇。
Eagerness in learning is close to intelligence.
Commitment in doing is close to nobleness.
Realization of shamefulness is close to courageousness.

[-- Attachment #2: atsc_epg_base_1278.patch --]
[-- Type: application/octet-stream, Size: 47116 bytes --]

# HG changeset patch
# User Yufei Yuan <yfyuan@gmail.com>
# Date 1245259744 18000
# Node ID 48605397912baf834f2ffbe95d44c51faed382c6
# Parent  ee4f2dbb8f28e93351d00aa38b0bd36469155769
Pulling ETT information can now be interrupted using Ctrl+C and still have partial printout.

diff -r ee4f2dbb8f28 -r 48605397912b util/atsc_epg/README
--- a/util/atsc_epg/README	Mon Jun 15 22:13:20 2009 -0500
+++ b/util/atsc_epg/README	Wed Jun 17 12:29:04 2009 -0500
@@ -3,6 +3,8 @@
 atsc_epg is a small utility for obtaining information such as programs, EPG 
 (electronic program guide) from an ATSC channel. 
 
+Pulling the detailed information, i.e., option '-t', may take fairly long time, or never ending, which is a bug of the PSIP generator. Ctrl+C can be used to abort and the received parts will be printed.
+
 Enjoy,
 Yufei
 
diff -r ee4f2dbb8f28 -r 48605397912b util/atsc_epg/atsc_epg.c
--- a/util/atsc_epg/atsc_epg.c	Mon Jun 15 22:13:20 2009 -0500
+++ b/util/atsc_epg/atsc_epg.c	Wed Jun 17 12:29:04 2009 -0500
@@ -23,6 +23,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <time.h>
+#include <signal.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -53,8 +54,10 @@
 static int period = 12; /* hours */
 static int frequency;
 static int enable_ett = 0;
+static int ctrl_c = 0;
 static const char *modulation = NULL;
 static char separator[80];
+void (*old_handler)(int);
 
 struct atsc_string_buffer {
     int buf_len;
@@ -75,6 +78,8 @@
 struct atsc_eit_section_info {
     uint8_t section_num;
     uint8_t num_events;
+    uint8_t num_etms;
+    uint8_t num_received_etms;
     struct atsc_event_info **events;
 };
 
@@ -161,6 +166,14 @@
     NULL, NULL
 };
 
+static void int_handler(int sig_num) 
+{
+    if(SIGINT != sig_num) {
+        return;
+    }
+    ctrl_c = 1;
+}
+
 /* shamelessly stolen from dvbsnoop, but modified */
 static uint32_t get_bits(const uint8_t *buf, int startbit, int bitlen)
 {
@@ -428,82 +441,100 @@
 
 static int parse_ett(int dmxfd, int index, uint16_t pid) 
 {
+    uint8_t curr_index;
+    uint32_t section_pattern;
     const enum atsc_section_tag tag = stag_atsc_extended_text;
+    struct atsc_eit_info *eit;
+    struct atsc_eit_section_info *section;
     struct atsc_ett_section *ett;
     struct atsc_channel_info *channel;
     struct atsc_event_info *event;
     struct atsc_text *text;
     struct atsc_text_string *str;
     uint16_t source_id, event_id;
-    int i, j, k, ret;
+    int i, j, k, c, ret;
 
-    ret = atsc_scan_table(dmxfd, pid, tag, (void **)&ett);
-    fprintf(stdout, ".");
-    fflush(stdout);
-    if(0 > ret) {
-        fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
-        return -1;
-    }
-    if(0 == ret) {
-        fprintf(stdout, "no EIT %d in %d seconds\n", index, TIMEOUT);
+    if(0xFFFF == guide.ett_pid[index]) {
         return 0;
     }
 
-    source_id = ett->ETM_source_id;
-    event_id = ett->ETM_sub_id;
-    channel = NULL;
-    for(i = 0; i < guide.num_channels; i++) {
-        if(source_id == guide.ch[i].src_id) {
-            channel = &guide.ch[i];
-            break;
-        }
-    }
-    if(NULL == channel) {
-        return 0;
-    }
+    for(c = 0; c < guide.num_channels; c++) {
+        channel = &guide.ch[c];
+        eit = &channel->eit[index];
 
-    event = NULL;
-    for(i = 0; i < channel->num_eits; i++) {
-        struct atsc_eit_info *eit = &channel->eit[i];
+        section_pattern = 0;
+        while(section_pattern != (uint32_t)((1 << eit->num_eit_sections) - 1)) {
+            if(ctrl_c) {
+                return 0;
+            }
+            ret = atsc_scan_table(dmxfd, pid, tag, (void **)&ett);
+            fprintf(stdout, ".");
+            fflush(stdout);
+            if(0 > ret) {
+                fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
+                return -1;
+            }
+            if(0 == ret) {
+                fprintf(stdout, "no ETT %d in %d seconds\n", index, TIMEOUT);
+                return 0;
+            }
 
-        for(j = 0; j < eit->num_eit_sections; j++) {
-            struct atsc_eit_section_info *section = &eit->section[j];
+            source_id = ett->ETM_source_id;
+            event_id = ett->ETM_sub_id;
+            if(source_id != channel->src_id) {
+                continue;
+            }
 
-            for(k = 0; k < section->num_events; k++) {
-                if(section->events[k] && section->events[k]->id == event_id) {
-                    event = section->events[k];
+            event = NULL;
+            for(j = 0; j < eit->num_eit_sections; j++) {
+                section = &eit->section[j];
+
+                for(k = 0; k < section->num_events; k++) {
+                    if(section->events[k] && section->events[k]->id == event_id) {
+                        event = section->events[k];
+                        break;
+                    }
+                }
+                if(event) {
+                    curr_index = j;
                     break;
                 }
             }
-            if(event) {
-                break;
+            if(NULL == event) {
+                continue;
+            }
+            if(section_pattern & (1 << curr_index)) {
+                /* the section has been filled, so skip, not consider version yet */
+                continue;
+            }
+            if(event->msg_len) {
+                /* the message has been filled */
+                continue;
+            }
+
+            text = atsc_ett_section_extended_text_message(ett);
+            atsc_text_strings_for_each(text, str, i) {
+                struct atsc_text_string_segment *seg;
+
+                atsc_text_string_segments_for_each(str, seg, j) {
+                    event->msg_pos = channel->msg_buf.buf_pos;
+                    if(0 > atsc_text_segment_decode(seg, 
+                        (uint8_t **)&channel->msg_buf.string, 
+                        (size_t *)&channel->msg_buf.buf_len, 
+                        (size_t *)&channel->msg_buf.buf_pos)) {
+                        fprintf(stderr, "%s(): error calling atsc_text_segment_decode()\n", 
+                            __FUNCTION__);
+                        return -1;
+                    }
+                    event->msg_len = 1 + channel->msg_buf.buf_pos - event->msg_pos;
+                }
+            }
+            if(++section->num_received_etms == section->num_etms) {
+                section_pattern |= 1 << curr_index;
             }
         }
-        if(event) {
-            break;
-        }
-    }
-    if(NULL == event) {
-        return 0;
     }
 
-    text = atsc_ett_section_extended_text_message(ett);
-    atsc_text_strings_for_each(text, str, i) {
-        struct atsc_text_string_segment *seg;
-
-        atsc_text_string_segments_for_each(str, seg, j) {
-            event->msg_pos = channel->msg_buf.buf_pos;
-            if(0 > atsc_text_segment_decode(seg, 
-                (uint8_t **)&channel->msg_buf.string, 
-                (size_t *)&channel->msg_buf.buf_len, 
-                (size_t *)&channel->msg_buf.buf_pos)) {
-                fprintf(stderr, "%s(): error calling atsc_text_segment_decode()\n", 
-                    __FUNCTION__);
-                return -1;
-            }
-            event->msg_len = 1 + channel->msg_buf.buf_pos - event->msg_pos;
-        }
-    }
     return 0;
 }
 
@@ -614,6 +645,8 @@
 
             section->section_num = section_num;
             section->num_events = eit->num_events_in_section;
+            section->num_etms = 0;
+            section->num_received_etms = 0;
             if(NULL == (section->events = calloc(section->num_events, 
                 sizeof(struct atsc_event_info *)))) {
                 fprintf(stderr, "%s(): error calling calloc()\n", __FUNCTION__);
@@ -639,6 +672,10 @@
                 end_time = start_time + e->length_in_seconds;
                 localtime_r(&start_time, &e_info->start);
                 localtime_r(&end_time, &e_info->end);
+                if(0 != e->ETM_location && 3 != e->ETM_location) {
+                    /* FIXME assume 1 and 2 is interchangable as of now */
+                    section->num_etms++;
+                }
 
                 title = atsc_eit_event_name_title_text(e);
                 atsc_text_strings_for_each(title, str, j) {
@@ -868,6 +905,9 @@
     pollfd.fd = dmxfd;
     pollfd.events = POLLIN | POLLERR |POLLPRI;
     if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
+        if(ctrl_c) {
+            return 0;
+        }
         fprintf(stderr, "%s(): error calling poll()\n", __FUNCTION__);
         return -1;
     }
@@ -1003,6 +1043,7 @@
     }
     fprintf(stdout, "\n");
 
+    old_handler = signal(SIGINT, int_handler);
     if(enable_ett) {
         fprintf(stdout, "receiving ETT ");
         for(i = 0; i < guide.ch[0].num_eits; i++) {
@@ -1012,9 +1053,13 @@
                     return -1;
                 }
             }
+            if(ctrl_c) {
+                break;
+            }
         }
         fprintf(stdout, "\n");
     }
+    signal(SIGINT, old_handler);
 
     if(print_guide()) {
         fprintf(stderr, "%s(): error calling print_guide()\n", __FUNCTION__);
# HG changeset patch
# User Yufei Yuan <yfyuan@gmail.com>
# Date 1245122000 18000
# Node ID ee4f2dbb8f28e93351d00aa38b0bd36469155769
# Parent  38609cb0d9c586c78a80b7173f80aa32e355a811
Help information print fixed.

diff -r 38609cb0d9c5 -r ee4f2dbb8f28 util/atsc_epg/atsc_epg.c
--- a/util/atsc_epg/atsc_epg.c	Mon Jun 15 20:32:08 2009 -0500
+++ b/util/atsc_epg/atsc_epg.c	Mon Jun 15 22:13:20 2009 -0500
@@ -187,15 +187,15 @@
 
 static void usage(void)
 {
-    fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p <period>][-m <modulation>] [-h]\n", 
-        program);
+    fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p <period>]" 
+        " [-m <modulation>] [-t] [-h]\n", program);
 }
 
 static void help(void)
 {
     fprintf(stderr,
     "\nhelp:\n"
-        "%s [-a <n>] -f <frequency> [-m <modulation>] [-t] [-h]\n"
+        "%s [-a <n>] -f <frequency> [-p <period>] [-m <modulation>] [-t] [-h]\n"
         "  -a: adapter index to use, (default 0)\n"
         "  -f: tuning frequency\n"
         "  -p: period in hours, (default 12)\n"
# HG changeset patch
# User Yufei Yuan <yfyuan@gmail.com>
# Date 1245115928 18000
# Node ID 38609cb0d9c586c78a80b7173f80aa32e355a811
# Parent  9b5c731498085a0f9e03242092f7489f5ac09230
1. A new utility atsc_epg is added.
2. Makefile and Perl script changed to be compiled with GCC 4.4.

diff -r 9b5c73149808 -r 38609cb0d9c5 util/Makefile
--- a/util/Makefile	Wed Jun 10 20:23:15 2009 +0200
+++ b/util/Makefile	Mon Jun 15 20:32:08 2009 -0500
@@ -3,6 +3,7 @@
 .PHONY: all clean install
 
 all clean install:
+	$(MAKE) -C atsc_epg $@
 	$(MAKE) -C av7110_loadkeys $@
 	$(MAKE) -C dib3000-watch $@
 	$(MAKE) -C dst-utils $@
diff -r 9b5c73149808 -r 38609cb0d9c5 util/atsc_epg/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/atsc_epg/Makefile	Mon Jun 15 20:32:08 2009 -0500
@@ -0,0 +1,15 @@
+# Makefile for linuxtv.org dvb-apps/util/atsc_epg
+
+binaries = atsc_epg
+
+inst_bin = $(binaries)
+
+CPPFLAGS += -I../../lib -std=c99 -D_POSIX_SOURCE
+LDFLAGS  += -static -L../../lib/libdvbapi -L../../lib/libucsi
+LDLIBS   += -ldvbapi -lucsi
+
+.PHONY: all
+
+all: $(binaries)
+
+include ../../Make.rules
diff -r 9b5c73149808 -r 38609cb0d9c5 util/atsc_epg/README
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/atsc_epg/README	Mon Jun 15 20:32:08 2009 -0500
@@ -0,0 +1,8 @@
+Hi there,
+
+atsc_epg is a small utility for obtaining information such as programs, EPG 
+(electronic program guide) from an ATSC channel. 
+
+Enjoy,
+Yufei
+
diff -r 9b5c73149808 -r 38609cb0d9c5 util/atsc_epg/atsc_epg.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/atsc_epg/atsc_epg.c	Mon Jun 15 20:32:08 2009 -0500
@@ -0,0 +1,1058 @@
+/*
+ * atsc_epg utility
+ * 
+ * Copyright (C) 2009 Yufei Yuan <yfyuan@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <libdvbapi/dvbfe.h>
+#include <libdvbapi/dvbdemux.h>
+#include <libucsi/dvb/section.h>
+#include <libucsi/atsc/section.h>
+#include <libucsi/atsc/types.h>
+
+#define TIMEOUT                     60
+#define RRT_TIMEOUT                 60
+#define MAX_NUM_EVENT_TABLES        128
+#define TITLE_BUFFER_LEN            4096
+#define MESSAGE_BUFFER_LEN          (16 * 1024)
+#define MAX_NUM_CHANNELS            16
+#define MAX_NUM_EVENTS_PER_CHANNEL  (4 * 24 * 7)
+
+static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag, 
+    void **table_section);
+
+static const char *program;
+static int adapter = 0;
+static int period = 12; /* hours */
+static int frequency;
+static int enable_ett = 0;
+static const char *modulation = NULL;
+static char separator[80];
+
+struct atsc_string_buffer {
+    int buf_len;
+    int buf_pos;
+    char *string;
+};
+
+struct atsc_event_info {
+    uint16_t id;
+    struct tm start;
+    struct tm end;
+    int title_pos;
+    int title_len;
+    int msg_pos;
+    int msg_len;
+};
+
+struct atsc_eit_section_info {
+    uint8_t section_num;
+    uint8_t num_events;
+    struct atsc_event_info **events;
+};
+
+struct atsc_eit_info {
+    int num_eit_sections;
+    struct atsc_eit_section_info *section;
+};
+
+struct atsc_channel_info {
+    uint8_t num_eits;
+    uint8_t service_type;
+    char short_name[8];
+    uint16_t major_num;
+    uint16_t minor_num;
+    uint16_t tsid;
+    uint16_t prog_num;
+    uint16_t src_id;
+    struct atsc_eit_info *eit;
+    struct atsc_event_info *last_event;
+    int event_info_index;
+    struct atsc_event_info e[MAX_NUM_EVENTS_PER_CHANNEL]; 
+    struct atsc_string_buffer title_buf;
+    struct atsc_string_buffer msg_buf;
+};
+
+struct atsc_virtual_channels_info {
+    int num_channels;
+    uint16_t eit_pid[MAX_NUM_EVENT_TABLES];
+    uint16_t ett_pid[MAX_NUM_EVENT_TABLES];
+    struct atsc_channel_info ch[MAX_NUM_CHANNELS];
+} guide;
+
+struct mgt_table_name {
+    uint16_t range;
+    const char *string;
+};
+
+struct mgt_table_name mgt_tab_name_array[] = {
+    {0x0000, "terrestrial VCT with current_next_indictor=1"},
+    {0x0001, "terrestrial VCT with current_next_indictor=0"},
+    {0x0002, "cable VCT with current_next_indictor=1"},
+    {0x0003, "cable VCT with current_next_indictor=0"},
+    {0x0004, "channel ETT"},
+    {0x0005, "DCCSCT"},
+    {0x00FF, "reserved for future ATSC use"},
+    {0x017F, "EIT"},
+    {0x01FF, "reserved for future ATSC use"},
+    {0x027F, "event ETT"},
+    {0x02FF, "reserved for future ATSC use"}, /* FIXME */
+    {0x03FF, "RRT with rating region"},
+    {0x0FFF, "user private"},
+    {0x13FF, "reserved for future ATSC use"},
+    {0x14FF, "DCCT with dcc_id"},
+    {0xFFFF, "reserved for future ATSC use"}
+};
+
+const char *channel_modulation_mode[] = {
+    "",
+    "analog",
+    "SCTE mode 1",
+    "SCTE mode 2",
+    "ATSC 8VSB",
+    "ATSC 16VSB"
+};
+
+const char *channel_service_type[] = {
+    "",
+    "analog TV",
+    "ATSC digital TV",
+    "ATSC audio",
+    "ATSC data-only"
+};
+
+void *(*table_callback[16])(struct atsc_section_psip *) = 
+{
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    (void *(*)(struct atsc_section_psip *))atsc_mgt_section_codec,
+    (void *(*)(struct atsc_section_psip *))atsc_tvct_section_codec,
+    (void *(*)(struct atsc_section_psip *))atsc_cvct_section_codec,
+    (void *(*)(struct atsc_section_psip *))atsc_rrt_section_codec,
+    (void *(*)(struct atsc_section_psip *))atsc_eit_section_codec,
+    (void *(*)(struct atsc_section_psip *))atsc_ett_section_codec,
+    (void *(*)(struct atsc_section_psip *))atsc_stt_section_codec,
+    NULL, NULL
+};
+
+/* shamelessly stolen from dvbsnoop, but modified */
+static uint32_t get_bits(const uint8_t *buf, int startbit, int bitlen)
+{
+    const uint8_t *b;
+    uint32_t mask,tmp_long;
+    int bitHigh,i;
+
+    b = &buf[startbit / 8];
+    startbit %= 8;
+
+    bitHigh = 8;
+    tmp_long = b[0];
+    for (i = 0; i < ((bitlen-1) >> 3); i++) {
+        tmp_long <<= 8;
+        tmp_long  |= b[i+1];
+        bitHigh   += 8;
+    }
+
+    startbit = bitHigh - startbit - bitlen;
+    tmp_long = tmp_long >> startbit;
+    mask     = (1ULL << bitlen) - 1;
+    return tmp_long & mask;
+}
+
+static void usage(void)
+{
+    fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p <period>][-m <modulation>] [-h]\n", 
+        program);
+}
+
+static void help(void)
+{
+    fprintf(stderr,
+    "\nhelp:\n"
+        "%s [-a <n>] -f <frequency> [-m <modulation>] [-t] [-h]\n"
+        "  -a: adapter index to use, (default 0)\n"
+        "  -f: tuning frequency\n"
+        "  -p: period in hours, (default 12)\n"
+        "  -m: modulation ATSC vsb_8|vsb_16 (default vsb_8)\n"
+        "  -t: enable ETT to receive program details, if available\n"
+        "  -h: display this message\n", program);
+}
+
+static int close_frontend(struct dvbfe_handle *fe)
+{
+    if(NULL == fe) {
+        fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+    }
+
+    dvbfe_close(fe);
+
+    return 0;
+}
+
+static int open_frontend(struct dvbfe_handle **fe)
+{
+    struct dvbfe_info fe_info;
+
+    if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
+        fprintf(stderr, "%s(): error calling dvbfe_open()\n", __FUNCTION__);
+        return -1;
+    }
+    dvbfe_get_info(*fe, 0, &fe_info, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
+    if(DVBFE_TYPE_ATSC != fe_info.type) {
+        fprintf(stderr, "%s(): only ATSC frontend supported currently\n", __FUNCTION__);
+        return -1;
+    }
+    fe_info.feparams.frequency = frequency;
+    fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
+    fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
+    fprintf(stdout, "tuning to %d Hz, please wait...\n", frequency);
+    if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
+        fprintf(stderr, "%s(): cannot lock to %d Hz in %d seconds\n", 
+            __FUNCTION__, frequency, TIMEOUT);
+        return -1;
+    }
+    fprintf(stdout, "tuner locked.\n");
+
+    return 0;
+}
+
+#if 0
+static int parse_rrt(int dmxfd)
+{
+    const enum atsc_section_tag tag = stag_atsc_rating_region;
+    struct atsc_rrt_section *rrt;
+    struct atsc_text *region_name;
+    struct atsc_text_string *atsc_str;
+    int i, j, ret;
+
+    i = 0;
+    fprintf(stdout, "waiting for RRT: ");
+    fflush(stdout);
+    while(i < RRT_TIMEOUT) {
+        ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&rrt);
+        if(0 > ret) {
+            fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
+            return -1;
+        }
+        if(0 == ret) {
+            if(RRT_TIMEOUT > i) {
+                fprintf(stdout, ".");
+                fflush(stdout);
+            } else {
+                fprintf(stdout, "\nno RRT in %d seconds\n", RRT_TIMEOUT);
+                return 0;
+            }
+            i += TIMEOUT;
+        } else {
+            fprintf(stdout, "\n");
+            fflush(stdout);
+            break;
+        }
+    }
+
+    region_name = atsc_rrt_section_rating_region_name_text(rrt);
+    atsc_text_strings_for_each(region_name, atsc_str, i) {
+        struct atsc_text_string_segment *seg;
+        atsc_text_string_segments_for_each(atsc_str, seg, j) {
+            const char *c;
+            int k;
+            if(seg->mode < 0x3E) {
+                fprintf(stderr, "%s(): text mode of 0x%02X not supported yet\n", 
+                    __FUNCTION__, seg->mode);
+                return -1;
+            }
+            c = (const char *)atsc_text_string_segment_bytes(seg);
+            for(k = 0; k < seg->number_bytes; k++) {
+                fprintf(stdout, "%c", c[k]);
+            }
+        }
+    }
+
+    return 0;
+}
+#endif
+
+static int parse_stt(int dmxfd)
+{
+    const enum atsc_section_tag tag = stag_atsc_system_time;
+    const struct atsc_stt_section *stt;
+    time_t rx_time;
+    time_t sys_time;
+    int ret;
+
+    ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&stt);
+    if(0 > ret) {
+        fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
+        return -1;
+    }
+    if(0 == ret) {
+        fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
+        return 0;
+    }
+
+    rx_time = atsctime_to_unixtime(stt->system_time);
+    time(&sys_time);
+    fprintf(stdout, "system time: %s", ctime(&sys_time));
+    fprintf(stdout, "TS STT time: %s", ctime(&rx_time));
+
+    return 0;
+}
+
+static int parse_tvct(int dmxfd) 
+{
+    int num_sections;
+    uint32_t section_pattern;
+    const enum atsc_section_tag tag = stag_atsc_terrestrial_virtual_channel;
+    struct atsc_tvct_section *tvct;
+    struct atsc_tvct_channel *ch;
+    struct atsc_channel_info *curr_info;
+    int i, k, ret;
+
+    section_pattern = 0;
+    num_sections = -1;
+
+    do {
+        ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&tvct);
+        if(0 > ret) {
+            fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
+            return -1;
+        }
+        if(0 == ret) {
+            fprintf(stdout, "no TVCT in %d seconds\n", TIMEOUT);
+            return 0;
+        }
+
+        if(-1 == num_sections) {
+            num_sections = 1 + tvct->head.ext_head.last_section_number;
+            if(32 < num_sections) {
+                fprintf(stderr, "%s(): no support yet for tables having more than " 
+                    "32 sections\n", __FUNCTION__);
+                return -1;
+            }
+        } else {
+            if(num_sections != 1 + tvct->head.ext_head.last_section_number) {
+                fprintf(stderr, "%s(): last section number does not match\n", 
+                    __FUNCTION__);
+                return -1;
+            }
+        }
+        if(section_pattern & (1 << tvct->head.ext_head.section_number)) {
+            continue;
+        }
+        section_pattern |= 1 << tvct->head.ext_head.section_number;
+
+        if(MAX_NUM_CHANNELS < guide.num_channels + tvct->num_channels_in_section) {
+            fprintf(stderr, "%s(): no support for more than %d virtual channels " 
+                "in a pyhsical channel\n", __FUNCTION__, MAX_NUM_CHANNELS);
+            return -1;
+        }
+        curr_info = &guide.ch[guide.num_channels];
+        guide.num_channels += tvct->num_channels_in_section;
+
+        atsc_tvct_section_channels_for_each(tvct, ch, i) {
+            /* initialize the curr_info structure */
+            /* each EIT covers 3 hours */
+            curr_info->num_eits = (period / 3) + !!(period % 3); 
+            while (curr_info->num_eits && 
+                (0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
+                curr_info->num_eits -= 1;
+            }
+            if(curr_info->eit) {
+                fprintf(stderr, "%s(): non-NULL pointer detected during initialization", 
+                    __FUNCTION__);
+                return -1;
+            }
+            if(NULL == (curr_info->eit = calloc(curr_info->num_eits, 
+                sizeof(struct atsc_eit_info)))) {
+                fprintf(stderr, "%s(): error calling calloc()\n", __FUNCTION__);
+                return -1;
+            }
+            if(NULL == (curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN, 
+                sizeof(char)))) {
+                fprintf(stderr, "%s(): error calling calloc()\n", __FUNCTION__);
+                return -1;
+            }
+            curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
+            curr_info->title_buf.buf_pos = 0;
+
+            if(NULL == (curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN, 
+                sizeof(char)))) {
+                fprintf(stderr, "%s(): error calling calloc()\n", __FUNCTION__);
+                return -1;
+            }
+            curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
+            curr_info->msg_buf.buf_pos = 0;
+
+            for(k = 0; k < 7; k++) {
+                curr_info->short_name[k] = get_bits((const uint8_t *)ch->short_name, 
+                    k * 16, 16);
+            }
+            curr_info->service_type = ch->service_type;
+            curr_info->major_num = ch->major_channel_number;
+            curr_info->minor_num = ch->minor_channel_number;
+            curr_info->tsid = ch->channel_TSID;
+            curr_info->prog_num = ch->program_number;
+            curr_info->src_id = ch->source_id;
+            curr_info++;
+        }
+    } while(section_pattern != (uint32_t)((1 << num_sections) - 1));
+
+    return 0;
+}
+
+static int parse_ett(int dmxfd, int index, uint16_t pid) 
+{
+    const enum atsc_section_tag tag = stag_atsc_extended_text;
+    struct atsc_ett_section *ett;
+    struct atsc_channel_info *channel;
+    struct atsc_event_info *event;
+    struct atsc_text *text;
+    struct atsc_text_string *str;
+    uint16_t source_id, event_id;
+    int i, j, k, ret;
+
+    ret = atsc_scan_table(dmxfd, pid, tag, (void **)&ett);
+    fprintf(stdout, ".");
+    fflush(stdout);
+    if(0 > ret) {
+        fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
+        return -1;
+    }
+    if(0 == ret) {
+        fprintf(stdout, "no EIT %d in %d seconds\n", index, TIMEOUT);
+        return 0;
+    }
+
+    source_id = ett->ETM_source_id;
+    event_id = ett->ETM_sub_id;
+    channel = NULL;
+    for(i = 0; i < guide.num_channels; i++) {
+        if(source_id == guide.ch[i].src_id) {
+            channel = &guide.ch[i];
+            break;
+        }
+    }
+    if(NULL == channel) {
+        return 0;
+    }
+
+    event = NULL;
+    for(i = 0; i < channel->num_eits; i++) {
+        struct atsc_eit_info *eit = &channel->eit[i];
+
+        for(j = 0; j < eit->num_eit_sections; j++) {
+            struct atsc_eit_section_info *section = &eit->section[j];
+
+            for(k = 0; k < section->num_events; k++) {
+                if(section->events[k] && section->events[k]->id == event_id) {
+                    event = section->events[k];
+                    break;
+                }
+            }
+            if(event) {
+                break;
+            }
+        }
+        if(event) {
+            break;
+        }
+    }
+    if(NULL == event) {
+        return 0;
+    }
+
+    text = atsc_ett_section_extended_text_message(ett);
+    atsc_text_strings_for_each(text, str, i) {
+        struct atsc_text_string_segment *seg;
+
+        atsc_text_string_segments_for_each(str, seg, j) {
+            event->msg_pos = channel->msg_buf.buf_pos;
+            if(0 > atsc_text_segment_decode(seg, 
+                (uint8_t **)&channel->msg_buf.string, 
+                (size_t *)&channel->msg_buf.buf_len, 
+                (size_t *)&channel->msg_buf.buf_pos)) {
+                fprintf(stderr, "%s(): error calling atsc_text_segment_decode()\n", 
+                    __FUNCTION__);
+                return -1;
+            }
+            event->msg_len = 1 + channel->msg_buf.buf_pos - event->msg_pos;
+        }
+    }
+    return 0;
+}
+
+static int parse_eit(int dmxfd, int index, uint16_t pid) 
+{
+    int num_sections;
+    uint8_t section_num;
+    uint8_t curr_channel_index;
+    uint32_t section_pattern;
+    const enum atsc_section_tag tag = stag_atsc_event_information;
+    struct atsc_eit_section *eit;
+    struct atsc_eit_event *e;
+    struct atsc_channel_info *curr_info;
+    struct atsc_eit_info *eit_info;
+    struct atsc_eit_section_info *section;
+    uint16_t source_id;
+    time_t start_time, end_time;
+    uint32_t eit_instance_pattern = 0;
+    int i, j, k, ret;
+
+    while(eit_instance_pattern != (uint32_t)((1 << guide.num_channels) - 1)) {
+        source_id = 0xFFFF;
+        section_pattern = 0;
+        num_sections = -1;
+
+        do {
+            ret = atsc_scan_table(dmxfd, pid, tag, (void **)&eit);
+            fprintf(stdout, ".");
+            fflush(stdout);
+            if(0 > ret) {
+                fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
+                return -1;
+            }
+            if(0 == ret) {
+                fprintf(stdout, "no EIT %d in %d seconds\n", index, TIMEOUT);
+                return 0;
+            }
+
+            if(0xFFFF == source_id) {
+                source_id = atsc_eit_section_source_id(eit);
+                for(k = 0; k < guide.num_channels; k++) {
+                    if(source_id == guide.ch[k].src_id) {
+                        curr_info = &guide.ch[k];
+                        curr_channel_index = k;
+                        if(0 == index) {
+                            curr_info->last_event = NULL;
+                        }
+                        break;
+                    }
+                }
+                if(k == guide.num_channels) {
+                    fprintf(stderr, "%s(): cannot find source_id 0x%04X in the EIT\n", 
+                        __FUNCTION__, source_id);
+                    return -1;
+                }
+            } else {
+                if(source_id != atsc_eit_section_source_id(eit)) {
+                    continue;
+                }
+            }
+            if(eit_instance_pattern & (1 << curr_channel_index)) {
+                /* we have received this instance, so quit quick */
+                break;
+            }
+
+            if(-1 == num_sections) {
+                num_sections = 1 + eit->head.ext_head.last_section_number;
+                if(32 < num_sections) {
+                    fprintf(stderr, "%s(): no support yet for tables having more than " 
+                        "32 sections\n", __FUNCTION__);
+                    return -1;
+                }
+            } else {
+                if(num_sections != 1 + eit->head.ext_head.last_section_number) {
+                    fprintf(stderr, "%s(): last section number does not match\n", 
+                        __FUNCTION__);
+                    return -1;
+                }
+            }
+            if(section_pattern & (1 << eit->head.ext_head.section_number)) {
+                continue;
+            }
+            section_pattern |= 1 << eit->head.ext_head.section_number;
+
+            eit_info = &curr_info->eit[index];
+            if(NULL == (eit_info->section = realloc(eit_info->section, 
+                (eit_info->num_eit_sections + 1) * sizeof(struct atsc_eit_section_info)))) {
+                fprintf(stderr, "%s(): error calling realloc()\n", __FUNCTION__);
+                return -1;
+            }
+            section_num = eit->head.ext_head.section_number;
+            if(0 == eit_info->num_eit_sections) {
+                eit_info->num_eit_sections = 1;
+                section = eit_info->section;
+            } else {
+                /* have to sort it into section order (temporal order) */
+                for(i = 0; i < eit_info->num_eit_sections; i++) {
+                    if(section_num < eit_info->section[i].section_num) {
+                        break;
+                    }
+                }
+                memmove(&eit_info->section[i + 1], &eit_info->section[i], 
+                    (eit_info->num_eit_sections - i) * sizeof(struct atsc_eit_section_info));
+                section = &eit_info->section[i - 1];
+                section = &eit_info->section[i];
+                eit_info->num_eit_sections += 1;
+            }
+
+            section->section_num = section_num;
+            section->num_events = eit->num_events_in_section;
+            if(NULL == (section->events = calloc(section->num_events, 
+                sizeof(struct atsc_event_info *)))) {
+                fprintf(stderr, "%s(): error calling calloc()\n", __FUNCTION__);
+                return -1;
+            }
+
+            atsc_eit_section_events_for_each(eit, e, i) {
+                struct atsc_text *title;
+                struct atsc_text_string *str;
+                struct atsc_event_info *e_info = &curr_info->e[curr_info->event_info_index];
+
+                if(0 == i && curr_info->last_event) {
+                    if(e->event_id == curr_info->last_event->id) {
+                        section->events[i] = NULL;
+                        /* skip if it's the same event spanning over sections */
+                        continue;
+                    }
+                }
+                curr_info->event_info_index += 1;
+                section->events[i] = e_info;
+                e_info->id = e->event_id;
+                start_time = atsctime_to_unixtime(e->start_time);
+                end_time = start_time + e->length_in_seconds;
+                localtime_r(&start_time, &e_info->start);
+                localtime_r(&end_time, &e_info->end);
+
+                title = atsc_eit_event_name_title_text(e);
+                atsc_text_strings_for_each(title, str, j) {
+                    struct atsc_text_string_segment *seg;
+
+                    atsc_text_string_segments_for_each(str, seg, k) {
+                        e_info->title_pos = curr_info->title_buf.buf_pos;
+                        if(0 > atsc_text_segment_decode(seg, 
+                            (uint8_t **)&curr_info->title_buf.string, 
+                            (size_t *)&curr_info->title_buf.buf_len, 
+                            (size_t *)&curr_info->title_buf.buf_pos)) {
+                            fprintf(stderr, "%s(): error calling atsc_text_segment_decode()\n", 
+                                __FUNCTION__);
+                            return -1;
+                        }
+                        e_info->title_len = 1 + curr_info->title_buf.buf_pos - 
+                            e_info->title_pos; 
+                    }
+                }
+            }
+        } while(section_pattern != (uint32_t)((1 << num_sections) - 1));
+        eit_instance_pattern |= 1 << curr_channel_index;
+    }
+
+    for(i = 0; i < guide.num_channels; i++) {
+        struct atsc_channel_info *channel = &guide.ch[i];
+        struct atsc_eit_info *ei = &channel->eit[index];
+        struct atsc_eit_section_info *s;
+
+        if(0 == ei->num_eit_sections) {
+            channel->last_event = NULL;
+            continue;
+        }
+        s = &ei->section[ei->num_eit_sections - 1];
+        /* BUG: it's incorrect when last section has no event */
+        if(0 == s->num_events) {
+            channel->last_event = NULL;
+            continue;
+        }
+        channel->last_event = s->events[s->num_events - 1];
+    }
+
+    return 0;
+}
+
+static int parse_mgt(int dmxfd)
+{
+    const enum atsc_section_tag tag = stag_atsc_master_guide;
+    struct atsc_mgt_section *mgt;
+    struct atsc_mgt_table *t;
+    int i, j, ret;
+
+    ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&mgt);
+    if(0 > ret) {
+        fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
+        return -1;
+    }
+    if(0 == ret) {
+        fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
+        return 0;
+    }
+
+    fprintf(stdout, "MGT table:\n");
+    atsc_mgt_section_tables_for_each(mgt, t, i) {
+        struct mgt_table_name table;
+
+        for(j = 0; j < (int)(sizeof(mgt_tab_name_array) / 
+            sizeof(struct mgt_table_name)); j++) {
+            if(t->table_type > mgt_tab_name_array[j].range) {
+                continue;
+            }
+            table = mgt_tab_name_array[j];
+            if(0 == j || mgt_tab_name_array[j - 1].range + 1 == 
+                mgt_tab_name_array[j].range) {
+                j = -1;
+            } else {
+                j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
+                if(0x017F == table.range) {
+                    guide.eit_pid[j] = t->table_type_PID;
+                } else if (0x027F == table.range) {
+                    guide.ett_pid[j] = t->table_type_PID;
+                }
+            }
+            break;
+        }
+
+        fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X, %s", i, 
+            t->table_type, t->table_type_PID, table.string);
+        if(-1 != j) {
+            fprintf(stdout, " %d", j);
+        }
+        fprintf(stdout, "\n");
+    }
+ 
+    return 0;
+}
+
+static int cleanup_guide(void) 
+{
+    int i, j, k;
+
+    for(i = 0; i < guide.num_channels; i++) {
+        struct atsc_channel_info *channel = &guide.ch[i];
+
+        if(channel->title_buf.string) {
+            free(channel->title_buf.string);
+        }
+        if(channel->msg_buf.string) {
+            free(channel->msg_buf.string);
+        }
+        for(j = 0; j < channel->num_eits; j++) {
+            struct atsc_eit_info *eit = &channel->eit[j];
+
+            for(k = 0; k < eit->num_eit_sections; k++) {
+                struct atsc_eit_section_info *section = &eit->section[k];
+                if(section->num_events) {
+                    free(section->events);
+                }
+            }
+            if(k) {
+                free(eit->section);
+            }
+        }
+        if(j) {
+            free(channel->eit);
+        }
+    }
+
+    return 0;
+}
+
+static int print_guide(void) 
+{
+    int i, j, k, m;
+    char line[256];
+
+    fprintf(stdout, "%s\n", separator);
+    for(i = 0; i < guide.num_channels; i++) {
+        struct atsc_channel_info *channel = &guide.ch[i];
+
+        fprintf(stdout, "%d.%d  %s\n", channel->major_num, channel->minor_num, 
+            channel->short_name);
+        for(j = 0; j < channel->num_eits; j++) {
+            struct atsc_eit_info *eit = &channel->eit[j];
+
+            for(k = 0; k < eit->num_eit_sections; k++) {
+                struct atsc_eit_section_info *section = &eit->section[k];
+
+                for(m = 0; m < section->num_events; m++) {
+                    struct atsc_event_info *event = section->events[m];
+
+                    if(NULL == event) {
+                        continue;
+                    }
+                    fprintf(stdout, "|%02d:%02d--%02d:%02d| ", 
+                        event->start.tm_hour, event->start.tm_min, 
+                        event->end.tm_hour, event->end.tm_min);
+                    snprintf(line, event->title_len, "%s", 
+                        &channel->title_buf.string[event->title_pos]);
+                    line[event->title_len] = '\0';
+                    fprintf(stdout, "%s\n", line);
+                    if(event->msg_len) {
+                        int len = event->msg_len;
+                        int pos = event->msg_pos;
+                        size_t part;
+                        do {
+                            part = len > 255 ? 255 : len;
+                            snprintf(line, part, "%s", 
+                                &channel->msg_buf.string[pos]);
+                            line[part] = '\0';
+                            fprintf(stdout, "%s", line);
+                            len -= part; pos += part;
+                        } while(0 < len);
+                        fprintf(stdout, "\n");
+                    }
+                }
+            }
+        }
+        fprintf(stdout, "%s\n", separator);
+    }
+
+    return 0;
+}
+
+static int open_demux(int *dmxfd)
+{
+    if ((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
+        fprintf(stderr, "%s(): error calling dvbdemux_open_demux()\n", __FUNCTION__);
+        return -1;
+    }
+    return 0;
+}
+
+static int close_demux(int dmxfd)
+{
+    if (dvbdemux_stop(dmxfd)) {
+        fprintf(stderr, "%s(): error calling dvbdemux_stop()\n", __FUNCTION__);
+        return -1;
+    }
+    return 0;
+}
+
+static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag, 
+    void **table_section)
+{
+    uint8_t filter[18];
+    uint8_t mask[18];
+    unsigned char sibuf[4096];
+    int size;
+    int ret;
+    struct pollfd pollfd;
+    struct section *section;
+    struct section_ext *section_ext;
+    struct atsc_section_psip *psip;
+
+    /* create a section filter for the table */
+    memset(filter, 0, sizeof(filter));
+    memset(mask, 0, sizeof(mask));
+    filter[0] = tag;
+    mask[0] = 0xFF;
+    if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
+        fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
+        return -1;
+    }
+
+    /* poll for data */
+    pollfd.fd = dmxfd;
+    pollfd.events = POLLIN | POLLERR |POLLPRI;
+    if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
+        fprintf(stderr, "%s(): error calling poll()\n", __FUNCTION__);
+        return -1;
+    }
+
+    if(0 == ret) {
+        return 0;
+    }
+
+    /* read it */
+    if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
+        fprintf(stderr, "%s(): error calling read()\n", __FUNCTION__);
+        return -1;
+    }
+
+    /* parse section */
+    section = section_codec(sibuf, size);
+    if(NULL == section) {
+        fprintf(stderr, "%s(): error calling section_codec()\n", __FUNCTION__);
+        return -1;
+    }
+
+    section_ext = section_ext_decode(section, 0);
+    if(NULL == section_ext) {
+        fprintf(stderr, "%s(): error calling section_ext_decode()\n", __FUNCTION__);
+        return -1;
+    }
+
+    psip = atsc_section_psip_decode(section_ext);
+    if(NULL == psip) {
+        fprintf(stderr, "%s(): error calling atsc_section_psip_decode()\n", __FUNCTION__);
+        return -1;
+    }
+
+    *table_section = table_callback[tag & 0x0F](psip);
+    if(NULL == *table_section) {
+        fprintf(stderr, "%s(): error decode table section\n", __FUNCTION__);
+        return -1;
+    }
+
+    return 1;
+}
+
+int main(int argc, char *argv[])
+{
+    int i, dmxfd;
+    struct dvbfe_handle *fe;
+
+    if(1 == argc) {
+        usage();
+    }
+
+    program = argv[0];
+
+    for( ; ; ) {
+        char c;
+
+        if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
+            break;
+        }
+
+        switch(c) {
+        case 'a':
+            adapter = strtoll(optarg, NULL, 0);
+            break;
+
+        case 'f':
+            frequency = strtol(optarg, NULL, 0);
+            break;
+
+        case 'p':
+            period = strtol(optarg, NULL, 0);
+            /* each table covers 3 hours */
+            if((3 * MAX_NUM_EVENT_TABLES) < period) {
+                period = 3 * MAX_NUM_EVENT_TABLES;
+            }
+            break;
+
+        case 'm':
+            modulation = optarg;
+            break;
+
+        case 't':
+            enable_ett = 1;
+            break;
+
+        case 'h':
+            help();
+            exit(0);
+
+        default:
+            usage();
+            exit(-1);
+        }
+    }
+
+    memset(separator, '-', sizeof(separator));
+    separator[79] = '\0';
+    memset(&guide, 0, sizeof(struct atsc_virtual_channels_info));
+    memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
+    memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
+
+    if(open_frontend(&fe)) {
+        fprintf(stderr, "%s(): error calling open_frontend()\n", __FUNCTION__);
+        return -1;
+    }
+
+    if(open_demux(&dmxfd)) {
+        fprintf(stderr, "%s(): error calling open_demux()\n", __FUNCTION__);
+        return -1;
+    }
+
+    if(parse_stt(dmxfd)) {
+        fprintf(stderr, "%s(): error calling parse_stt()\n", __FUNCTION__);
+        return -1;
+    }
+
+    if(parse_mgt(dmxfd)) {
+        fprintf(stderr, "%s(): error calling parse_mgt()\n", __FUNCTION__);
+        return -1;
+    }
+
+    if(parse_tvct(dmxfd)) {
+        fprintf(stderr, "%s(): error calling parse_tvct()\n", __FUNCTION__);
+        return -1;
+    }
+
+    fprintf(stdout, "receiving EIT ");
+    for(i = 0; i < guide.ch[0].num_eits; i++) {
+        if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
+            fprintf(stderr, "%s(): error calling parse_eit()\n", __FUNCTION__);
+            return -1;
+        }
+    }
+    fprintf(stdout, "\n");
+
+    if(enable_ett) {
+        fprintf(stdout, "receiving ETT ");
+        for(i = 0; i < guide.ch[0].num_eits; i++) {
+            if(0xFFFF != guide.ett_pid[i]) {
+                if(parse_ett(dmxfd, i, guide.ett_pid[i])) {
+                    fprintf(stderr, "%s(): error calling parse_eit()\n", __FUNCTION__);
+                    return -1;
+                }
+            }
+        }
+        fprintf(stdout, "\n");
+    }
+
+    if(print_guide()) {
+        fprintf(stderr, "%s(): error calling print_guide()\n", __FUNCTION__);
+        return -1;
+    }
+
+    if(cleanup_guide()) {
+        fprintf(stderr, "%s(): error calling cleanup_guide()\n", __FUNCTION__);
+        return -1;
+    }
+
+#if 0
+    i = 0;
+    while(0 != ch_info[i].source_id) {
+        ch_info[i].string[ch_info[i].buffer_pos] = '\0';
+        fprintf(stdout, "%s", ch_info[i].string);
+        free(ch_info[i++].string);
+    }
+    fprintf(stdout, "%s\n", separator);
+#endif
+
+#if 0
+    if(parse_rrt(dmxfd)) {
+        fprintf(stderr, "%s(): error calling parse_rrt()\n", __FUNCTION__);
+        return -1;
+    }
+#endif
+
+    if(close_demux(dmxfd)) {
+        fprintf(stderr, "%s(): error calling close_demux()\n", __FUNCTION__);
+        return -1;
+    }
+
+    if(close_frontend(fe)) {
+        fprintf(stderr, "%s(): error calling close_demux()\n", __FUNCTION__);
+        return -1;
+    }
+
+    return 0;
+}
+
diff -r 9b5c73149808 -r 38609cb0d9c5 util/scan/Makefile
--- a/util/scan/Makefile	Wed Jun 10 20:23:15 2009 +0200
+++ b/util/scan/Makefile	Mon Jun 15 20:32:08 2009 -0500
@@ -14,7 +14,7 @@
 
 removing = atsc_psip_section.c atsc_psip_section.h
 
-CPPFLAGS += -DDATADIR=\"$(prefix)/share\"
+CPPFLAGS += -D__KERNEL_STRICT_NAMES -DDATADIR=\"$(prefix)/share\"
 
 .PHONY: all
 
diff -r 9b5c73149808 -r 38609cb0d9c5 util/scan/atsc_psip_section.pl
--- a/util/scan/atsc_psip_section.pl	Wed Jun 10 20:23:15 2009 +0200
+++ b/util/scan/atsc_psip_section.pl	Mon Jun 15 20:32:08 2009 -0500
@@ -65,10 +65,11 @@
 				hidden => 1,
 				reserved1 => 2,
 				hide_guide => 1,
-				reserved2 => 3,
+				reserved2 => 1,
+				reserved3 => 2,
 				service_type => 6,
 				source_id => 16,
-				reserved3 => 6,
+				reserved4 => 6,
 				descriptors_length => 10,
 			],
 		},

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-17 23:18 [Patch] New utility program atsc_epg added to dvb-apps utility suite Yufei Yuan
@ 2009-06-17 23:51 ` hermann pitton
       [not found]   ` <ccdf9f470906171706gc36e43bq4e2092d948c1fbf5@mail.gmail.com>
  2009-06-18  8:32 ` Manu Abraham
  1 sibling, 1 reply; 22+ messages in thread
From: hermann pitton @ 2009-06-17 23:51 UTC (permalink / raw)
  To: Yufei Yuan; +Cc: Linux Media Mailing List


Am Mittwoch, den 17.06.2009, 18:18 -0500 schrieb Yufei Yuan:
> Hi,
> 
> I am not sure if this is the correct mailing list to send this patch.
> >From the LinuxTV website, it seems that currently dvb-apps project
> has
> no owner.
> 
> A new utility atsc_epg is added into the dvb-apps utility suite. It
> parses PSIP information carried in OTA ATSC channels, and constructs a
> basic EPG in a terminal window. Changes were also made to files to
> please GCC4.4.
> 
> The patch is against latest revision 1278 from the dvb-apps
> repository.
> 
> Regards,
> Yufei Yuan
> 
> -- 
> 好学近乎智,力行近乎仁,知耻近乎勇。
> Eagerness in learning is close to intelligence.
> Commitment in doing is close to nobleness.
> Realization of shamefulness is close to courageousness.

Getting engaged into footers ...

The above blindly assumes that there is a balance within that reduction
to three cases ... (we know two are enough)

You miss at least several hundred years of history on the other side of
the planet.

I totally disagree with that kind of stuff.

Most explicitly with the third variant.

That way you can still press any slave into any army ...








^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
       [not found]       ` <ccdf9f470906171720i4076642dna483643c55a4a85f@mail.gmail.com>
@ 2009-06-18  0:52         ` hermann pitton
       [not found]         ` <1245285015.10476.4.camel@pc07.localdom.local>
  1 sibling, 0 replies; 22+ messages in thread
From: hermann pitton @ 2009-06-18  0:52 UTC (permalink / raw)
  To: Yufei Yuan, linux-media

Hi,

Am Mittwoch, den 17.06.2009, 19:20 -0500 schrieb Yufei Yuan:
> If you take such an intolerant attitude against what others opinion
> might be, your words might just be deemed worthless, or should I say
> *bullshit*, by others. It is really sad that this world is never in
> shortage of people like you.
> 
> What a shame of humanity.
> 
> Regards,

yes, feel free to speak up.

I do the same and do hate medieval age footers ;)

Why that stuff is not filtered here ???

Cheers,
Hermann

> 
> On Wed, Jun 17, 2009 at 7:14 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
> > Hi,
> >
> > Am Mittwoch, den 17.06.2009, 19:06 -0500 schrieb Yufei Yuan:
> >> Sorry I guess this is about the way the patch was generated? Or about
> >> the utility itself?
> >>
> >> Regards,
> >
> > most likely.
> >
> > And that is what I exactly do mean.
> >
> > Obviously you don't have any control about the footers others provide
> > for you, if you go shopping ;)
> >
> > --
> > 好学近乎智,力行近乎仁,知耻近乎勇。
> > Eagerness in learning is close to intelligence.
> > Commitment in doing is close to nobleness.
> > Realization of shamefulness is close to courageousness.
> >
> > :)
> >
> > what a bullshit.
> >
> > Cheers,
> > Hermann
> >
> >>
> >> On Wed, Jun 17, 2009 at 6:51 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
> >> >
> >> > Am Mittwoch, den 17.06.2009, 18:18 -0500 schrieb Yufei Yuan:
> >> >> Hi,
> >> >>
> >> >> I am not sure if this is the correct mailing list to send this patch.
> >> >> >From the LinuxTV website, it seems that currently dvb-apps project
> >> >> has
> >> >> no owner.
> >> >>
> >> >> A new utility atsc_epg is added into the dvb-apps utility suite. It
> >> >> parses PSIP information carried in OTA ATSC channels, and constructs a
> >> >> basic EPG in a terminal window. Changes were also made to files to
> >> >> please GCC4.4.
> >> >>
> >> >> The patch is against latest revision 1278 from the dvb-apps
> >> >> repository.
> >> >>
> >> >> Regards,
> >> >> Yufei Yuan
> >> >>
> >> >> --
> >> >> 好学近乎智,力行近乎仁,知耻近乎勇。
> >> >> Eagerness in learning is close to intelligence.
> >> >> Commitment in doing is close to nobleness.
> >> >> Realization of shamefulness is close to courageousness.
> >> >
> >> > Getting engaged into footers ...
> >> >
> >> > The above blindly assumes that there is a balance within that reduction
> >> > to three cases ... (we know two are enough)
> >> >
> >> > You miss at least several hundred years of history on the other side of
> >> > the planet.
> >> >
> >> > I totally disagree with that kind of stuff.
> >> >
> >> > Most explicitly with the third variant.
> >> >
> >> > That way you can still press any slave into any army ...
> >> >



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
       [not found]           ` <ccdf9f470906171746k8e5ac37j9c0a48823f98ba87@mail.gmail.com>
@ 2009-06-18  1:05             ` hermann pitton
  2009-06-18  1:12               ` Yufei Yuan
  0 siblings, 1 reply; 22+ messages in thread
From: hermann pitton @ 2009-06-18  1:05 UTC (permalink / raw)
  To: Yufei Yuan, linux-media

Am Mittwoch, den 17.06.2009, 19:46 -0500 schrieb Yufei Yuan:
> Age would cure neither naivety nor stupidity. I would imagine only a
> self-important white supremacist would utter such comments in public
> against a total stranger. If you can read the Chinese above, I
> *seriously* doubt that, it's what Confucious said around 500BC, to
> encourage learning and repentance.

That was of course totally clear and exactly that is the annoyance !

> 
> I may not do a good job in translation, sorry about that. But blindly
> interpret other's intention based on one's own narrow personal
> experience, or cultural context, is the origin of the trouble between
> groups and nations, in this case, two individuals.

OK, let's keep the footers uncensored ;)

> Regards,
> 
> On Wed, Jun 17, 2009 at 7:30 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
> >
> > Am Mittwoch, den 17.06.2009, 19:20 -0500 schrieb Yufei Yuan:
> >> If you take such an intolerant attitude against what others opinion
> >> might be, your words might just be deemed worthless, or should I say
> >> *bullshit*, by others. It is really sad that this world is never in
> >> shortage of people like you.
> >>
> >> What a shame of humanity.
> >>
> >> Regards,
> >
> > I'm a German born in 1957.
> >
> > If that could help you any further in the future not to claim to have
> > the three golden rules ...
> >
> > Cheers,
> > Hermann
> >
> >>
> >> On Wed, Jun 17, 2009 at 7:14 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
> >> > Hi,
> >> >
> >> > Am Mittwoch, den 17.06.2009, 19:06 -0500 schrieb Yufei Yuan:
> >> >> Sorry I guess this is about the way the patch was generated? Or about
> >> >> the utility itself?
> >> >>
> >> >> Regards,
> >> >
> >> > most likely.
> >> >
> >> > And that is what I exactly do mean.
> >> >
> >> > Obviously you don't have any control about the footers others provide
> >> > for you, if you go shopping ;)
> >> >
> >> > --
> >> > 好学近乎智,力行近乎仁,知耻近乎勇。
> >> > Eagerness in learning is close to intelligence.
> >> > Commitment in doing is close to nobleness.
> >> > Realization of shamefulness is close to courageousness.
> >> >
> >> > :)
> >> >
> >> > what a bullshit.
> >> >
> >> > Cheers,
> >> > Hermann
> >> >
> >> >>
> >> >> On Wed, Jun 17, 2009 at 6:51 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
> >> >> >
> >> >> > Am Mittwoch, den 17.06.2009, 18:18 -0500 schrieb Yufei Yuan:
> >> >> >> Hi,
> >> >> >>
> >> >> >> I am not sure if this is the correct mailing list to send this patch.
> >> >> >> >From the LinuxTV website, it seems that currently dvb-apps project
> >> >> >> has
> >> >> >> no owner.
> >> >> >>
> >> >> >> A new utility atsc_epg is added into the dvb-apps utility suite. It
> >> >> >> parses PSIP information carried in OTA ATSC channels, and constructs a
> >> >> >> basic EPG in a terminal window. Changes were also made to files to
> >> >> >> please GCC4.4.
> >> >> >>
> >> >> >> The patch is against latest revision 1278 from the dvb-apps
> >> >> >> repository.
> >> >> >>
> >> >> >> Regards,
> >> >> >> Yufei Yuan
> >> >> >>
> >> >> >> --
> >> >> >> 好学近乎智,力行近乎仁,知耻近乎勇。
> >> >> >> Eagerness in learning is close to intelligence.
> >> >> >> Commitment in doing is close to nobleness.
> >> >> >> Realization of shamefulness is close to courageousness.
> >> >> >
> >> >> > Getting engaged into footers ...
> >> >> >
> >> >> > The above blindly assumes that there is a balance within that reduction
> >> >> > to three cases ... (we know two are enough)
> >> >> >
> >> >> > You miss at least several hundred years of history on the other side of
> >> >> > the planet.
> >> >> >
> >> >> > I totally disagree with that kind of stuff.
> >> >> >
> >> >> > Most explicitly with the third variant.
> >> >> >
> >> >> > That way you can still press any slave into any army ...
> >> >> >
> >
> >
> >
> 
> 
> 


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-18  1:05             ` hermann pitton
@ 2009-06-18  1:12               ` Yufei Yuan
  2009-06-18  1:23                 ` hermann pitton
  0 siblings, 1 reply; 22+ messages in thread
From: Yufei Yuan @ 2009-06-18  1:12 UTC (permalink / raw)
  To: hermann pitton; +Cc: linux-media

Okay, you win. Apology to others in the list who have to endure the
garbage talk.

Regards,
Yufei Yuan

On Wed, Jun 17, 2009 at 8:05 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
> Am Mittwoch, den 17.06.2009, 19:46 -0500 schrieb Yufei Yuan:
>> Age would cure neither naivety nor stupidity. I would imagine only a
>> self-important white supremacist would utter such comments in public
>> against a total stranger. If you can read the Chinese above, I
>> *seriously* doubt that, it's what Confucious said around 500BC, to
>> encourage learning and repentance.
>
> That was of course totally clear and exactly that is the annoyance !
>
>>
>> I may not do a good job in translation, sorry about that. But blindly
>> interpret other's intention based on one's own narrow personal
>> experience, or cultural context, is the origin of the trouble between
>> groups and nations, in this case, two individuals.
>
> OK, let's keep the footers uncensored ;)
>
>> Regards,
>>
>> On Wed, Jun 17, 2009 at 7:30 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
>> >
>> > Am Mittwoch, den 17.06.2009, 19:20 -0500 schrieb Yufei Yuan:
>> >> If you take such an intolerant attitude against what others opinion
>> >> might be, your words might just be deemed worthless, or should I say
>> >> *bullshit*, by others. It is really sad that this world is never in
>> >> shortage of people like you.
>> >>
>> >> What a shame of humanity.
>> >>
>> >> Regards,
>> >
>> > I'm a German born in 1957.
>> >
>> > If that could help you any further in the future not to claim to have
>> > the three golden rules ...
>> >
>> > Cheers,
>> > Hermann
>> >
>> >>
>> >> On Wed, Jun 17, 2009 at 7:14 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
>> >> > Hi,
>> >> >
>> >> > Am Mittwoch, den 17.06.2009, 19:06 -0500 schrieb Yufei Yuan:
>> >> >> Sorry I guess this is about the way the patch was generated? Or about
>> >> >> the utility itself?
>> >> >>
>> >> >> Regards,
>> >> >
>> >> > most likely.
>> >> >
>> >> > And that is what I exactly do mean.
>> >> >
>> >> > Obviously you don't have any control about the footers others provide
>> >> > for you, if you go shopping ;)
>> >> >
>> >> > --
>> >> > 好学近乎智,力行近乎仁,知耻近乎勇。
>> >> > Eagerness in learning is close to intelligence.
>> >> > Commitment in doing is close to nobleness.
>> >> > Realization of shamefulness is close to courageousness.
>> >> >
>> >> > :)
>> >> >
>> >> > what a bullshit.
>> >> >
>> >> > Cheers,
>> >> > Hermann
>> >> >
>> >> >>
>> >> >> On Wed, Jun 17, 2009 at 6:51 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
>> >> >> >
>> >> >> > Am Mittwoch, den 17.06.2009, 18:18 -0500 schrieb Yufei Yuan:
>> >> >> >> Hi,
>> >> >> >>
>> >> >> >> I am not sure if this is the correct mailing list to send this patch.
>> >> >> >> >From the LinuxTV website, it seems that currently dvb-apps project
>> >> >> >> has
>> >> >> >> no owner.
>> >> >> >>
>> >> >> >> A new utility atsc_epg is added into the dvb-apps utility suite. It
>> >> >> >> parses PSIP information carried in OTA ATSC channels, and constructs a
>> >> >> >> basic EPG in a terminal window. Changes were also made to files to
>> >> >> >> please GCC4.4.
>> >> >> >>
>> >> >> >> The patch is against latest revision 1278 from the dvb-apps
>> >> >> >> repository.
>> >> >> >>
>> >> >> >> Regards,
>> >> >> >> Yufei Yuan
>> >> >> >>
>> >> >> >> --
>> >> >> >> 好学近乎智,力行近乎仁,知耻近乎勇。
>> >> >> >> Eagerness in learning is close to intelligence.
>> >> >> >> Commitment in doing is close to nobleness.
>> >> >> >> Realization of shamefulness is close to courageousness.
>> >> >> >
>> >> >> > Getting engaged into footers ...
>> >> >> >
>> >> >> > The above blindly assumes that there is a balance within that reduction
>> >> >> > to three cases ... (we know two are enough)
>> >> >> >
>> >> >> > You miss at least several hundred years of history on the other side of
>> >> >> > the planet.
>> >> >> >
>> >> >> > I totally disagree with that kind of stuff.
>> >> >> >
>> >> >> > Most explicitly with the third variant.
>> >> >> >
>> >> >> > That way you can still press any slave into any army ...
>> >> >> >
>> >
>> >
>> >
>>
>>
>>
>
>



-- 
好学近乎智,力行近乎仁,知耻近乎勇。
Eagerness in learning is close to intelligence.
Commitment in doing is close to nobleness.
Realization of shamefulness is close to courageousness.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-18  1:12               ` Yufei Yuan
@ 2009-06-18  1:23                 ` hermann pitton
  0 siblings, 0 replies; 22+ messages in thread
From: hermann pitton @ 2009-06-18  1:23 UTC (permalink / raw)
  To: Yufei Yuan; +Cc: linux-media


Am Mittwoch, den 17.06.2009, 20:12 -0500 schrieb Yufei Yuan:
> Okay, you win. Apology to others in the list who have to endure the
> garbage talk.
> 
> Regards,
> Yufei Yuan

Sorry for abusing you for a ride out on mail footers.

Best,
Hermann

> 
> On Wed, Jun 17, 2009 at 8:05 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
> > Am Mittwoch, den 17.06.2009, 19:46 -0500 schrieb Yufei Yuan:
> >> Age would cure neither naivety nor stupidity. I would imagine only a
> >> self-important white supremacist would utter such comments in public
> >> against a total stranger. If you can read the Chinese above, I
> >> *seriously* doubt that, it's what Confucious said around 500BC, to
> >> encourage learning and repentance.
> >
> > That was of course totally clear and exactly that is the annoyance !
> >
> >>
> >> I may not do a good job in translation, sorry about that. But blindly
> >> interpret other's intention based on one's own narrow personal
> >> experience, or cultural context, is the origin of the trouble between
> >> groups and nations, in this case, two individuals.
> >
> > OK, let's keep the footers uncensored ;)
> >
> >> Regards,
> >>
> >> On Wed, Jun 17, 2009 at 7:30 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
> >> >
> >> > Am Mittwoch, den 17.06.2009, 19:20 -0500 schrieb Yufei Yuan:
> >> >> If you take such an intolerant attitude against what others opinion
> >> >> might be, your words might just be deemed worthless, or should I say
> >> >> *bullshit*, by others. It is really sad that this world is never in
> >> >> shortage of people like you.
> >> >>
> >> >> What a shame of humanity.
> >> >>
> >> >> Regards,
> >> >
> >> > I'm a German born in 1957.
> >> >
> >> > If that could help you any further in the future not to claim to have
> >> > the three golden rules ...
> >> >
> >> > Cheers,
> >> > Hermann
> >> >
> >> >>
> >> >> On Wed, Jun 17, 2009 at 7:14 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
> >> >> > Hi,
> >> >> >
> >> >> > Am Mittwoch, den 17.06.2009, 19:06 -0500 schrieb Yufei Yuan:
> >> >> >> Sorry I guess this is about the way the patch was generated? Or about
> >> >> >> the utility itself?
> >> >> >>
> >> >> >> Regards,
> >> >> >
> >> >> > most likely.
> >> >> >
> >> >> > And that is what I exactly do mean.
> >> >> >
> >> >> > Obviously you don't have any control about the footers others provide
> >> >> > for you, if you go shopping ;)
> >> >> >
> >> >> > --
> >> >> > 好学近乎智,力行近乎仁,知耻近乎勇。
> >> >> > Eagerness in learning is close to intelligence.
> >> >> > Commitment in doing is close to nobleness.
> >> >> > Realization of shamefulness is close to courageousness.
> >> >> >
> >> >> > :)
> >> >> >
> >> >> > what a bullshit.
> >> >> >
> >> >> > Cheers,
> >> >> > Hermann
> >> >> >
> >> >> >>
> >> >> >> On Wed, Jun 17, 2009 at 6:51 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
> >> >> >> >
> >> >> >> > Am Mittwoch, den 17.06.2009, 18:18 -0500 schrieb Yufei Yuan:
> >> >> >> >> Hi,
> >> >> >> >>
> >> >> >> >> I am not sure if this is the correct mailing list to send this patch.
> >> >> >> >> >From the LinuxTV website, it seems that currently dvb-apps project
> >> >> >> >> has
> >> >> >> >> no owner.
> >> >> >> >>
> >> >> >> >> A new utility atsc_epg is added into the dvb-apps utility suite. It
> >> >> >> >> parses PSIP information carried in OTA ATSC channels, and constructs a
> >> >> >> >> basic EPG in a terminal window. Changes were also made to files to
> >> >> >> >> please GCC4.4.
> >> >> >> >>
> >> >> >> >> The patch is against latest revision 1278 from the dvb-apps
> >> >> >> >> repository.
> >> >> >> >>
> >> >> >> >> Regards,
> >> >> >> >> Yufei Yuan
> >> >> >> >>
> >> >> >> >> --
> >> >> >> >> 好学近乎智,力行近乎仁,知耻近乎勇。
> >> >> >> >> Eagerness in learning is close to intelligence.
> >> >> >> >> Commitment in doing is close to nobleness.
> >> >> >> >> Realization of shamefulness is close to courageousness.
> >> >> >> >
> >> >> >> > Getting engaged into footers ...
> >> >> >> >
> >> >> >> > The above blindly assumes that there is a balance within that reduction
> >> >> >> > to three cases ... (we know two are enough)
> >> >> >> >
> >> >> >> > You miss at least several hundred years of history on the other side of
> >> >> >> > the planet.
> >> >> >> >
> >> >> >> > I totally disagree with that kind of stuff.
> >> >> >> >
> >> >> >> > Most explicitly with the third variant.
> >> >> >> >
> >> >> >> > That way you can still press any slave into any army ...
> >> >> >> >
> >> >
> >> >
> >> >
> >>
> >>
> >>
> >
> >
> 
> 
> 


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-17 23:18 [Patch] New utility program atsc_epg added to dvb-apps utility suite Yufei Yuan
  2009-06-17 23:51 ` hermann pitton
@ 2009-06-18  8:32 ` Manu Abraham
  2009-06-18  8:48   ` Manu Abraham
  1 sibling, 1 reply; 22+ messages in thread
From: Manu Abraham @ 2009-06-18  8:32 UTC (permalink / raw)
  To: Yufei Yuan; +Cc: Linux Media Mailing List

2009/6/18 Yufei Yuan <yfyuan@gmail.com>:
> Hi,
>
> I am not sure if this is the correct mailing list to send this patch.
> From the LinuxTV website, it seems that currently dvb-apps project has
> no owner.
>
> A new utility atsc_epg is added into the dvb-apps utility suite. It
> parses PSIP information carried in OTA ATSC channels, and constructs a
> basic EPG in a terminal window. Changes were also made to files to
> please GCC4.4.
>
> The patch is against latest revision 1278 from the dvb-apps repository.


Please do send the patch with tabs instead of spaces for indentation.

Regards,
Manu

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-18  8:32 ` Manu Abraham
@ 2009-06-18  8:48   ` Manu Abraham
  2009-06-18 13:06     ` Yufei Yuan
  0 siblings, 1 reply; 22+ messages in thread
From: Manu Abraham @ 2009-06-18  8:48 UTC (permalink / raw)
  To: Yufei Yuan; +Cc: Linux Media Mailing List

On Thu, Jun 18, 2009 at 12:32 PM, Manu Abraham<abraham.manu@gmail.com> wrote:
> 2009/6/18 Yufei Yuan <yfyuan@gmail.com>:
>> Hi,
>>
>> I am not sure if this is the correct mailing list to send this patch.
>> From the LinuxTV website, it seems that currently dvb-apps project has
>> no owner.
>>
>> A new utility atsc_epg is added into the dvb-apps utility suite. It
>> parses PSIP information carried in OTA ATSC channels, and constructs a
>> basic EPG in a terminal window. Changes were also made to files to
>> please GCC4.4.
>>
>> The patch is against latest revision 1278 from the dvb-apps repository.
>
>
> Please do send the patch with tabs instead of spaces for indentation.

Also:

* please cleanup the white spaces in the patch, if any.
* please use the unified format, diff -u option.

Regards,
Manu

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-18  8:48   ` Manu Abraham
@ 2009-06-18 13:06     ` Yufei Yuan
  2009-06-19  0:52       ` Yufei Yuan
  0 siblings, 1 reply; 22+ messages in thread
From: Yufei Yuan @ 2009-06-18 13:06 UTC (permalink / raw)
  To: Manu Abraham; +Cc: Linux Media Mailing List

Ok, I guess I violated at least coding style rule No.1, :) Will peruse
the coding style page tonight and redo the submission.

Regards,
Yufei

On Thu, Jun 18, 2009 at 3:48 AM, Manu Abraham<abraham.manu@gmail.com> wrote:
> On Thu, Jun 18, 2009 at 12:32 PM, Manu Abraham<abraham.manu@gmail.com> wrote:
>> 2009/6/18 Yufei Yuan <yfyuan@gmail.com>:
>>> Hi,
>>>
>>> I am not sure if this is the correct mailing list to send this patch.
>>> From the LinuxTV website, it seems that currently dvb-apps project has
>>> no owner.
>>>
>>> A new utility atsc_epg is added into the dvb-apps utility suite. It
>>> parses PSIP information carried in OTA ATSC channels, and constructs a
>>> basic EPG in a terminal window. Changes were also made to files to
>>> please GCC4.4.
>>>
>>> The patch is against latest revision 1278 from the dvb-apps repository.
>>
>>
>> Please do send the patch with tabs instead of spaces for indentation.
>
> Also:
>
> * please cleanup the white spaces in the patch, if any.
> * please use the unified format, diff -u option.
>
> Regards,
> Manu
>



-- 
好学近乎智,力行近乎仁,知耻近乎勇。
Eagerness in learning is close to intelligence.
Commitment in doing is close to nobleness.
Realization of shamefulness is close to courageousness.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-18 13:06     ` Yufei Yuan
@ 2009-06-19  0:52       ` Yufei Yuan
  2009-06-19  1:39         ` Yufei Yuan
  0 siblings, 1 reply; 22+ messages in thread
From: Yufei Yuan @ 2009-06-19  0:52 UTC (permalink / raw)
  To: Manu Abraham; +Cc: Linux Media Mailing List

Okay, this one serves as a test as well. It's a trivial one to fix the
broken dvb-apps building process with gcc4.4 on kernel 2.6.30, another
way to eliminate the packed bitfield warning is to split the field,
but that is unwanted.

previous build error:

make[2]: Entering directory `/home/alex/source/dvb-apps/util/scan'
perl section_generate.pl atsc_psip_section.pl
CC scan.o
In file included from scan.c:48:
atsc_psip_section.h:57: note: Offset of packed bit-field ‘reserved2’
has changed in GCC 4.4
CC atsc_psip_section.o
In file included from atsc_psip_section.c:2:
atsc_psip_section.h:57: note: Offset of packed bit-field ‘reserved2’
has changed in GCC 4.4
CC diseqc.o
In file included from diseqc.c:4:
/usr/include/time.h:104: error: conflicting types for ‘timer_t’
/usr/include/linux/types.h:22: note: previous declaration of ‘timer_t’ was here
make[2]: *** [diseqc.o] Error 1
make[2]: Leaving directory `/home/alex/source/dvb-apps/util/scan'
make[1]: *** [all] Error 2
make[1]: Leaving directory `/home/alex/source/dvb-apps/util'
make: *** [all] Error 2

--- dvb-apps/util/scan/Makefile.orig    2009-06-18 19:43:52.397924757 -0500
+++ dvb-apps/util/scan/Makefile 2009-06-18 19:44:34.764925070 -0500
@@ -14,7 +14,7 @@ inst_bin = $(binaries)

 removing = atsc_psip_section.c atsc_psip_section.h

-CPPFLAGS += -DDATADIR=\"$(prefix)/share\"
+CPPFLAGS += -Wno-packed-bitfield-compat -D__KERNEL_STRICT_NAMES
-DDATADIR=\"$(prefix)/share\"

 .PHONY: all




-- 
Even uttering "HI" or "HAO" is offensive, sometime, somewhere. Reader
discretion is advised.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-19  0:52       ` Yufei Yuan
@ 2009-06-19  1:39         ` Yufei Yuan
  2009-06-20  0:41           ` hermann pitton
       [not found]           ` <ccdf9f470906181855m2d6c471cm12afea3f228fd57c@mail.gmail.com>
  0 siblings, 2 replies; 22+ messages in thread
From: Yufei Yuan @ 2009-06-19  1:39 UTC (permalink / raw)
  To: Manu Abraham; +Cc: Linux Media Mailing List

This one is about the utility itself. I do apologize for the length
here as "inline" patch is preferred according to the guide and I don't
have any public online storage. Please let me know if this causes any
inconvenience.

Signed-off-by: Yufei Yuan <yfyuan@gmail.com>

diff -uprN dvb-apps/util/atsc_epg/atsc_epg.c
dvb-apps_new/util/atsc_epg/atsc_epg.c
--- dvb-apps/util/atsc_epg/atsc_epg.c   1969-12-31 18:00:00.000000000
-0600
+++ dvb-apps_new/util/atsc_epg/atsc_epg.c       2009-06-18
20:17:24.527925142 -0500
@@ -0,0 +1,1249 @@
+/*
+ * atsc_epg utility
+ *
+ * Copyright (C) 2009 Yufei Yuan <yfyuan@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <libdvbapi/dvbfe.h>
+#include <libdvbapi/dvbdemux.h>
+#include <libucsi/dvb/section.h>
+#include <libucsi/atsc/section.h>
+#include <libucsi/atsc/types.h>
+
+#define TIMEOUT                                60
+#define RRT_TIMEOUT                    60
+#define MAX_NUM_EVENT_TABLES           128
+#define TITLE_BUFFER_LEN               4096
+#define MESSAGE_BUFFER_LEN             (16 * 1024)
+#define MAX_NUM_CHANNELS               16
+#define MAX_NUM_EVENTS_PER_CHANNEL     (4 * 24 * 7)
+
+static int atsc_scan_table(int dmxfd, uint16_t pid, enum
atsc_section_tag tag,
+       void **table_section);
+
+static const char *program;
+static int adapter = 0;
+static int period = 12; /* hours */
+static int frequency;
+static int enable_ett = 0;
+static int ctrl_c = 0;
+static const char *modulation = NULL;
+static char separator[80];
+void (*old_handler)(int);
+
+struct atsc_string_buffer {
+       int buf_len;
+       int buf_pos;
+       char *string;
+};
+
+struct atsc_event_info {
+       uint16_t id;
+       struct tm start;
+       struct tm end;
+       int title_pos;
+       int title_len;
+       int msg_pos;
+       int msg_len;
+};
+
+struct atsc_eit_section_info {
+       uint8_t section_num;
+       uint8_t num_events;
+       uint8_t num_etms;
+       uint8_t num_received_etms;
+       struct atsc_event_info **events;
+};
+
+struct atsc_eit_info {
+       int num_eit_sections;
+       struct atsc_eit_section_info *section;
+};
+
+struct atsc_channel_info {
+       uint8_t num_eits;
+       uint8_t service_type;
+       char short_name[8];
+       uint16_t major_num;
+       uint16_t minor_num;
+       uint16_t tsid;
+       uint16_t prog_num;
+       uint16_t src_id;
+       struct atsc_eit_info *eit;
+       struct atsc_event_info *last_event;
+       int event_info_index;
+       struct atsc_event_info e[MAX_NUM_EVENTS_PER_CHANNEL];
+       struct atsc_string_buffer title_buf;
+       struct atsc_string_buffer msg_buf;
+};
+
+struct atsc_virtual_channels_info {
+       int num_channels;
+       uint16_t eit_pid[MAX_NUM_EVENT_TABLES];
+       uint16_t ett_pid[MAX_NUM_EVENT_TABLES];
+       struct atsc_channel_info ch[MAX_NUM_CHANNELS];
+} guide;
+
+struct mgt_table_name {
+       uint16_t range;
+       const char *string;
+};
+
+struct mgt_table_name mgt_tab_name_array[] = {
+       {0x0000, "terrestrial VCT with current_next_indictor=1"},
+       {0x0001, "terrestrial VCT with current_next_indictor=0"},
+       {0x0002, "cable VCT with current_next_indictor=1"},
+       {0x0003, "cable VCT with current_next_indictor=0"},
+       {0x0004, "channel ETT"},
+       {0x0005, "DCCSCT"},
+       {0x00FF, "reserved for future ATSC use"},
+       {0x017F, "EIT"},
+       {0x01FF, "reserved for future ATSC use"},
+       {0x027F, "event ETT"},
+       {0x02FF, "reserved for future ATSC use"}, /* FIXME */
+       {0x03FF, "RRT with rating region"},
+       {0x0FFF, "user private"},
+       {0x13FF, "reserved for future ATSC use"},
+       {0x14FF, "DCCT with dcc_id"},
+       {0xFFFF, "reserved for future ATSC use"}
+};
+
+const char *channel_modulation_mode[] = {
+       "",
+       "analog",
+       "SCTE mode 1",
+       "SCTE mode 2",
+       "ATSC 8VSB",
+       "ATSC 16VSB"
+};
+
+const char *channel_service_type[] = {
+       "",
+       "analog TV",
+       "ATSC digital TV",
+       "ATSC audio",
+       "ATSC data-only"
+};
+
+void *(*table_callback[16])(struct atsc_section_psip *) =
+{
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       (void *(*)(struct atsc_section_psip *))atsc_mgt_section_codec,
+       (void *(*)(struct atsc_section_psip
*))atsc_tvct_section_codec,
+       (void *(*)(struct atsc_section_psip
*))atsc_cvct_section_codec,
+       (void *(*)(struct atsc_section_psip *))atsc_rrt_section_codec,
+       (void *(*)(struct atsc_section_psip *))atsc_eit_section_codec,
+       (void *(*)(struct atsc_section_psip *))atsc_ett_section_codec,
+       (void *(*)(struct atsc_section_psip *))atsc_stt_section_codec,
+       NULL, NULL
+};
+
+static void int_handler(int sig_num)
+{
+       if(SIGINT != sig_num) {
+               return;
+       }
+       ctrl_c = 1;
+}
+
+/* shamelessly stolen from dvbsnoop, but almost not modified */
+static uint32_t get_bits(const uint8_t *buf, int startbit, int
bitlen)
+{
+       const uint8_t *b;
+       uint32_t mask,tmp_long;
+       int bitHigh,i;
+
+       b = &buf[startbit / 8];
+       startbit %= 8;
+
+       bitHigh = 8;
+       tmp_long = b[0];
+       for (i = 0; i < ((bitlen-1) >> 3); i++) {
+               tmp_long <<= 8;
+               tmp_long  |= b[i+1];
+               bitHigh   += 8;
+       }
+
+       startbit = bitHigh - startbit - bitlen;
+       tmp_long = tmp_long >> startbit;
+       mask     = (1ULL << bitlen) - 1;
+       return tmp_long & mask;
+}
+
+static void usage(void)
+{
+       fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p
<period>]"
+               " [-m <modulation>] [-t] [-h]\n", program);
+}
+
+static void help(void)
+{
+       fprintf(stderr,
+       "\nhelp:\n"
+       "%s [-a <n>] -f <frequency> [-p <period>] [-m <modulation>]
[-t] [-h]\n"
+       "  -a: adapter index to use, (default 0)\n"
+       "  -f: tuning frequency\n"
+       "  -p: period in hours, (default 12)\n"
+       "  -m: modulation ATSC vsb_8|vsb_16 (default vsb_8)\n"
+       "  -t: enable ETT to receive program details, if available\n"
+       "  -h: display this message\n", program);
+}
+
+static int close_frontend(struct dvbfe_handle *fe)
+{
+       if(NULL == fe) {
+               fprintf(stderr, "%s(): NULL pointer detected\n",
__FUNCTION__);
+       }
+
+       dvbfe_close(fe);
+
+       return 0;
+}
+
+static int open_frontend(struct dvbfe_handle **fe)
+{
+       struct dvbfe_info fe_info;
+
+       if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
+               fprintf(stderr, "%s(): error calling dvbfe_open()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+       dvbfe_get_info(*fe, 0, &fe_info,
DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
+       if(DVBFE_TYPE_ATSC != fe_info.type) {
+               fprintf(stderr, "%s(): only ATSC frontend supported
currently\n",
+                       __FUNCTION__);
+               return -1;
+       }
+       fe_info.feparams.frequency = frequency;
+       fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
+       fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
+       fprintf(stdout, "tuning to %d Hz, please wait...\n",
frequency);
+       if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
+               fprintf(stderr, "%s(): cannot lock to %d Hz in %d
seconds\n",
+                       __FUNCTION__, frequency, TIMEOUT);
+               return -1;
+       }
+       fprintf(stdout, "tuner locked.\n");
+
+       return 0;
+}
+
+#if ENABLE_RRT
+/* this is untested as since this part of the library is broken */
+static int parse_rrt(int dmxfd)
+{
+       const enum atsc_section_tag tag = stag_atsc_rating_region;
+       struct atsc_rrt_section *rrt;
+       struct atsc_text *region_name;
+       struct atsc_text_string *atsc_str;
+       int i, j, ret;
+
+       i = 0;
+       fprintf(stdout, "waiting for RRT: ");
+       fflush(stdout);
+       while(i < RRT_TIMEOUT) {
+               ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
**)&rrt);
+               if(0 > ret) {
+                       fprintf(stderr, "%s(): error calling
atsc_scan_table()\n",
+                               __FUNCTION__);
+                       return -1;
+               }
+               if(0 == ret) {
+                       if(RRT_TIMEOUT > i) {
+                               fprintf(stdout, ".");
+                               fflush(stdout);
+                       } else {
+                               fprintf(stdout, "\nno RRT in %d
seconds\n",
+                                       RRT_TIMEOUT);
+                               return 0;
+                       }
+                       i += TIMEOUT;
+               } else {
+                       fprintf(stdout, "\n");
+                       fflush(stdout);
+                       break;
+               }
+       }
+
+       region_name = atsc_rrt_section_rating_region_name_text(rrt);
+       atsc_text_strings_for_each(region_name, atsc_str, i) {
+               struct atsc_text_string_segment *seg;
+
+               atsc_text_string_segments_for_each(atsc_str, seg, j) {
+                       const char *c;
+                       int k;
+                       if(seg->mode < 0x3E) {
+                               fprintf(stderr, "%s(): text mode of
0x%02X "
+                                       "not supported yet\n",
+                                       __FUNCTION__, seg->mode);
+                               return -1;
+                       }
+                       c = (const char
*)atsc_text_string_segment_bytes(seg);
+                       for(k = 0; k < seg->number_bytes; k++) {
+                               fprintf(stdout, "%c", c[k]);
+                       }
+               }
+       }
+
+       return 0;
+}
+#endif
+
+static int parse_stt(int dmxfd)
+{
+       const enum atsc_section_tag tag = stag_atsc_system_time;
+       const struct atsc_stt_section *stt;
+       time_t rx_time;
+       time_t sys_time;
+       int ret;
+
+       ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
**)&stt);
+       if(0 > ret) {
+               fprintf(stderr, "%s(): error calling
atsc_scan_table()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+       if(0 == ret) {
+               fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
+               return 0;
+       }
+
+       rx_time = atsctime_to_unixtime(stt->system_time);
+       time(&sys_time);
+       fprintf(stdout, "system time: %s", ctime(&sys_time));
+       fprintf(stdout, "TS STT time: %s", ctime(&rx_time));
+
+       return 0;
+}
+
+static int parse_tvct(int dmxfd)
+{
+       int num_sections;
+       uint32_t section_pattern;
+       const enum atsc_section_tag tag =
stag_atsc_terrestrial_virtual_channel;
+       struct atsc_tvct_section *tvct;
+       struct atsc_tvct_channel *ch;
+       struct atsc_channel_info *curr_info;
+       int i, k, ret;
+
+       section_pattern = 0;
+       num_sections = -1;
+
+       do {
+               ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
**)&tvct);
+               if(0 > ret) {
+                       fprintf(stderr, "%s(): error calling
atsc_scan_table()\n",
+                       __FUNCTION__);
+                       return -1;
+               }
+               if(0 == ret) {
+                       fprintf(stdout, "no TVCT in %d seconds\n",
TIMEOUT);
+                       return 0;
+               }
+
+               if(-1 == num_sections) {
+                       num_sections = 1 +
tvct->head.ext_head.last_section_number;
+                       if(32 < num_sections) {
+                               fprintf(stderr, "%s(): no support yet
for "
+                                       "tables having more than 32
sections\n",
+                                       __FUNCTION__);
+                               return -1;
+                       }
+               } else {
+                       if(num_sections !=
+                               1 +
tvct->head.ext_head.last_section_number) {
+                               fprintf(stderr,
+                                       "%s(): last section number
does not match\n",
+                                       __FUNCTION__);
+                               return -1;
+                       }
+               }
+               if(section_pattern & (1 <<
tvct->head.ext_head.section_number)) {
+                       continue;
+               }
+               section_pattern |= 1 <<
tvct->head.ext_head.section_number;
+
+               if(MAX_NUM_CHANNELS < guide.num_channels +
+                       tvct->num_channels_in_section) {
+                       fprintf(stderr, "%s(): no support for more
than %d "
+                               "virtual channels in a pyhsical
channel\n",
+                               __FUNCTION__, MAX_NUM_CHANNELS);
+                       return -1;
+               }
+               curr_info = &guide.ch[guide.num_channels];
+               guide.num_channels += tvct->num_channels_in_section;
+
+       atsc_tvct_section_channels_for_each(tvct, ch, i) {
+               /* initialize the curr_info structure */
+               /* each EIT covers 3 hours */
+               curr_info->num_eits = (period / 3) + !!(period % 3);
+               while (curr_info->num_eits &&
+                       (0xFFFF == guide.eit_pid[curr_info->num_eits -
1])) {
+                       curr_info->num_eits -= 1;
+               }
+               if(curr_info->eit) {
+                       fprintf(stderr, "%s(): non-NULL pointer
detected "
+                               "during initialization",
__FUNCTION__);
+                       return -1;
+               }
+               if(NULL == (curr_info->eit =
calloc(curr_info->num_eits,
+                       sizeof(struct atsc_eit_info)))) {
+                       fprintf(stderr, "%s(): error calling
calloc()\n",
+                               __FUNCTION__);
+                       return -1;
+               }
+               if(NULL == (curr_info->title_buf.string =
calloc(TITLE_BUFFER_LEN,
+                       sizeof(char)))) {
+                       fprintf(stderr, "%s(): error calling
calloc()\n",
+                               __FUNCTION__);
+                       return -1;
+               }
+               curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
+               curr_info->title_buf.buf_pos = 0;
+
+               if(NULL == (curr_info->msg_buf.string =
calloc(MESSAGE_BUFFER_LEN,
+                       sizeof(char)))) {
+                       fprintf(stderr, "%s(): error calling
calloc()\n",
+                               __FUNCTION__);
+                       return -1;
+               }
+               curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
+               curr_info->msg_buf.buf_pos = 0;
+
+               for(k = 0; k < 7; k++) {
+                       curr_info->short_name[k] =
+                               get_bits((const uint8_t
*)ch->short_name,
+                               k * 16, 16);
+               }
+               curr_info->service_type = ch->service_type;
+               curr_info->major_num = ch->major_channel_number;
+               curr_info->minor_num = ch->minor_channel_number;
+               curr_info->tsid = ch->channel_TSID;
+               curr_info->prog_num = ch->program_number;
+               curr_info->src_id = ch->source_id;
+               curr_info++;
+               }
+       } while(section_pattern != (uint32_t)((1 << num_sections) -
1));
+
+       return 0;
+}
+
+static int match_event(struct atsc_eit_info *eit, uint16_t event_id,
+       struct atsc_event_info **event, uint8_t *curr_index)
+{
+       int j, k;
+       struct atsc_eit_section_info *section;
+
+       if(NULL == eit || NULL == event || NULL == curr_index) {
+               fprintf(stderr, "%s(): NULL pointer detected\n",
__FUNCTION__);
+               return -1;
+       }
+
+       for(j = 0; j < eit->num_eit_sections; j++) {
+               section = &eit->section[j];
+
+               for(k = 0; k < section->num_events; k++) {
+                       if(section->events[k] &&
section->events[k]->id ==
+                               event_id) {
+                               *event = section->events[k];
+                               break;
+                       }
+               }
+               if(*event) {
+                       *curr_index = j;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int parse_message(struct atsc_channel_info *channel,
+       struct atsc_ett_section *ett, struct atsc_event_info *event)
+{
+       int i, j;
+       struct atsc_text *text;
+       struct atsc_text_string *str;
+
+       if(NULL == ett || NULL == event || NULL == channel) {
+               fprintf(stderr, "%s(): NULL pointer detected\n",
__FUNCTION__);
+               return -1;
+       }
+
+       text = atsc_ett_section_extended_text_message(ett);
+       atsc_text_strings_for_each(text, str, i) {
+               struct atsc_text_string_segment *seg;
+
+               atsc_text_string_segments_for_each(str, seg, j) {
+                       event->msg_pos = channel->msg_buf.buf_pos;
+                       if(0 > atsc_text_segment_decode(seg,
+                               (uint8_t **)&channel->msg_buf.string,
+                               (size_t *)&channel->msg_buf.buf_len,
+                               (size_t *)&channel->msg_buf.buf_pos))
{
+                               fprintf(stderr, "%s(): error calling "
+
"atsc_text_segment_decode()\n",
+                                       __FUNCTION__);
+                               return -1;
+                       }
+                       event->msg_len = 1 + channel->msg_buf.buf_pos
-
+                               event->msg_pos;
+               }
+       }
+
+       return 0;
+}
+
+static int parse_ett(int dmxfd, int index, uint16_t pid)
+{
+       uint8_t curr_index;
+       uint32_t section_pattern;
+       const enum atsc_section_tag tag = stag_atsc_extended_text;
+       struct atsc_eit_info *eit;
+       struct atsc_ett_section *ett;
+       struct atsc_channel_info *channel;
+       struct atsc_event_info *event;
+       struct atsc_eit_section_info *section;
+       uint16_t source_id, event_id;
+       int c, ret;
+
+       if(0xFFFF == guide.ett_pid[index]) {
+               return 0;
+       }
+
+       for(c = 0; c < guide.num_channels; c++) {
+               channel = &guide.ch[c];
+               eit = &channel->eit[index];
+
+               section_pattern = 0;
+               while(section_pattern !=
+                       (uint32_t)((1 << eit->num_eit_sections) - 1))
{
+                       if(ctrl_c) {
+                               return 0;
+                       }
+                       ret = atsc_scan_table(dmxfd, pid, tag, (void
**)&ett);
+                       fprintf(stdout, ".");
+                       fflush(stdout);
+                       if(0 > ret) {
+                               fprintf(stderr, "%s(): error calling "
+                                       "atsc_scan_table()\n",
__FUNCTION__);
+                               return -1;
+                       }
+                       if(0 == ret) {
+                               fprintf(stdout, "no ETT %d in %d
seconds\n",
+                                       index, TIMEOUT);
+                               return 0;
+                       }
+
+                       source_id = ett->ETM_source_id;
+                       event_id = ett->ETM_sub_id;
+                       if(source_id != channel->src_id) {
+                               continue;
+                       }
+
+                       event = NULL;
+                       if(match_event(eit, event_id, &event,
&curr_index)) {
+                               fprintf(stderr, "%s(): error calling "
+                                       "match_event()\n",
__FUNCTION__);
+                               return -1;
+                       }
+                       if(NULL == event) {
+                               continue;
+                       }
+                       if(section_pattern & (1 << curr_index)) {
+                               /* the section has been filled, so
skip,
+                                * not consider version yet
+                                */
+                               continue;
+                       }
+                       if(event->msg_len) {
+                               /* the message has been filled */
+                               continue;
+                       }
+
+                       if(parse_message(channel, ett, event)) {
+                               fprintf(stderr, "%s(): error calling "
+                                       "parse_message()\n",
__FUNCTION__);
+                               return -1;
+                       }
+                       section = &eit->section[curr_index];
+                       if(++section->num_received_etms ==
section->num_etms) {
+                               section_pattern |= 1 << curr_index;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int parse_events(struct atsc_channel_info *curr_info,
+       struct atsc_eit_section *eit, struct atsc_eit_section_info
*section)
+{
+       int i, j, k;
+       struct atsc_eit_event *e;
+       time_t start_time, end_time;
+
+       if(NULL == curr_info || NULL == eit) {
+               fprintf(stderr, "%s(): NULL pointer detected\n",
__FUNCTION__);
+               return -1;
+       }
+
+       atsc_eit_section_events_for_each(eit, e, i) {
+               struct atsc_text *title;
+               struct atsc_text_string *str;
+               struct atsc_event_info *e_info =
+                       &curr_info->e[curr_info->event_info_index];
+
+               if(0 == i && curr_info->last_event) {
+                       if(e->event_id == curr_info->last_event->id) {
+                               section->events[i] = NULL;
+                               /* skip if it's the same event
spanning
+                                * over sections
+                                */
+                               continue;
+                       }
+               }
+               curr_info->event_info_index += 1;
+               section->events[i] = e_info;
+               e_info->id = e->event_id;
+               start_time = atsctime_to_unixtime(e->start_time);
+               end_time = start_time + e->length_in_seconds;
+               localtime_r(&start_time, &e_info->start);
+               localtime_r(&end_time, &e_info->end);
+               if(0 != e->ETM_location && 3 != e->ETM_location) {
+                       /* FIXME assume 1 and 2 is interchangable as
of now */
+                       section->num_etms++;
+               }
+
+               title = atsc_eit_event_name_title_text(e);
+               atsc_text_strings_for_each(title, str, j) {
+                       struct atsc_text_string_segment *seg;
+
+                       atsc_text_string_segments_for_each(str, seg,
k) {
+                               e_info->title_pos =
curr_info->title_buf.buf_pos;
+                               if(0 > atsc_text_segment_decode(seg,
+                                       (uint8_t
**)&curr_info->title_buf.string,
+                                       (size_t
*)&curr_info->title_buf.buf_len,
+                                       (size_t
*)&curr_info->title_buf.buf_pos)) {
+                                       fprintf(stderr, "%s(): error
calling "
+
"atsc_text_segment_decode()\n",
+                                               __FUNCTION__);
+                                       return -1;
+                               }
+                               e_info->title_len =
curr_info->title_buf.buf_pos -
+                                       e_info->title_pos + 1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int parse_eit(int dmxfd, int index, uint16_t pid)
+{
+       int num_sections;
+       uint8_t section_num;
+       uint8_t curr_channel_index;
+       uint32_t section_pattern;
+       const enum atsc_section_tag tag = stag_atsc_event_information;
+       struct atsc_eit_section *eit;
+       struct atsc_channel_info *curr_info;
+       struct atsc_eit_info *eit_info;
+       struct atsc_eit_section_info *section;
+       uint16_t source_id;
+       uint32_t eit_instance_pattern = 0;
+       int i, k, ret;
+
+       while(eit_instance_pattern !=
+               (uint32_t)((1 << guide.num_channels) - 1)) {
+               source_id = 0xFFFF;
+               section_pattern = 0;
+               num_sections = -1;
+
+               do {
+                       ret = atsc_scan_table(dmxfd, pid, tag, (void
**)&eit);
+                       fprintf(stdout, ".");
+                       fflush(stdout);
+                       if(0 > ret) {
+                               fprintf(stderr, "%s(): error calling "
+                                       "atsc_scan_table()\n",
__FUNCTION__);
+                               return -1;
+                       }
+                       if(0 == ret) {
+                               fprintf(stdout, "no EIT %d in %d
seconds\n",
+                                       index, TIMEOUT);
+                               return 0;
+                       }
+
+                       if(0xFFFF == source_id) {
+                       source_id = atsc_eit_section_source_id(eit);
+                       for(k = 0; k < guide.num_channels; k++) {
+                               if(source_id == guide.ch[k].src_id) {
+                                       curr_info = &guide.ch[k];
+                                       curr_channel_index = k;
+                                       if(0 == index) {
+                                               curr_info->last_event
= NULL;
+                                       }
+                                       break;
+                               }
+                       }
+                       if(k == guide.num_channels) {
+                               fprintf(stderr, "%s(): cannot find
source_id "
+                                       "0x%04X in the EIT\n",
+                                       __FUNCTION__, source_id);
+                               return -1;
+                       }
+                       } else {
+                               if(source_id !=
+
atsc_eit_section_source_id(eit)) {
+                                       continue;
+                               }
+                       }
+                       if(eit_instance_pattern & (1 <<
curr_channel_index)) {
+                               /* we have received this instance,
+                                * so quit quick
+                                */
+                               break;
+                       }
+
+                       if(-1 == num_sections) {
+                               num_sections = 1 +
+
eit->head.ext_head.last_section_number;
+                               if(32 < num_sections) {
+                                       fprintf(stderr,
+                                               "%s(): no support yet
for "
+                                               "tables having more
than "
+                                               "32 sections\n",
__FUNCTION__);
+                                       return -1;
+                               }
+                       } else {
+                               if(num_sections != 1 +
+
eit->head.ext_head.last_section_number) {
+                                       fprintf(stderr,
+                                               "%s(): last section
number "
+                                               "does not match\n",
+                                               __FUNCTION__);
+                                       return -1;
+                               }
+                       }
+                       if(section_pattern &
+                               (1 <<
eit->head.ext_head.section_number)) {
+                               continue;
+                       }
+                       section_pattern |= 1 <<
eit->head.ext_head.section_number;
+
+                       eit_info = &curr_info->eit[index];
+                       if(NULL == (eit_info->section =
+                               realloc(eit_info->section,
+                               (eit_info->num_eit_sections + 1) *
+                               sizeof(struct
atsc_eit_section_info)))) {
+                               fprintf(stderr,
+                                       "%s(): error calling
realloc()\n",
+                                       __FUNCTION__);
+                               return -1;
+                       }
+                       section_num =
eit->head.ext_head.section_number;
+                       if(0 == eit_info->num_eit_sections) {
+                               eit_info->num_eit_sections = 1;
+                               section = eit_info->section;
+                       } else {
+                               /* have to sort it into section order
+                                * (temporal order)
+                                */
+                               for(i = 0; i <
eit_info->num_eit_sections; i++) {
+
if(eit_info->section[i].section_num >
+                                               section_num) {
+                                               break;
+                                       }
+                               }
+                               memmove(&eit_info->section[i + 1],
+                                       &eit_info->section[i],
+                                       (eit_info->num_eit_sections -
i) *
+                                       sizeof(struct
atsc_eit_section_info));
+                               section = &eit_info->section[i - 1];
+                               section = &eit_info->section[i];
+                               eit_info->num_eit_sections += 1;
+                       }
+
+                       section->section_num = section_num;
+                       section->num_events =
eit->num_events_in_section;
+                       section->num_etms = 0;
+                       section->num_received_etms = 0;
+                       if(NULL == (section->events =
calloc(section->num_events,
+                               sizeof(struct atsc_event_info *)))) {
+                               fprintf(stderr, "%s(): error calling
calloc()\n",
+                                       __FUNCTION__);
+                               return -1;
+                       }
+                       if(parse_events(curr_info, eit, section)) {
+                               fprintf(stderr, "%s(): error calling "
+                                       "parse_events()\n",
__FUNCTION__);
+                               return -1;
+                       }
+               } while(section_pattern != (uint32_t)((1 <<
num_sections) - 1));
+               eit_instance_pattern |= 1 << curr_channel_index;
+       }
+
+       for(i = 0; i < guide.num_channels; i++) {
+               struct atsc_channel_info *channel = &guide.ch[i];
+               struct atsc_eit_info *ei = &channel->eit[index];
+               struct atsc_eit_section_info *s;
+
+               if(0 == ei->num_eit_sections) {
+                       channel->last_event = NULL;
+                       continue;
+               }
+               s = &ei->section[ei->num_eit_sections - 1];
+               /* BUG: it's incorrect when last section has no event
*/
+               if(0 == s->num_events) {
+                       channel->last_event = NULL;
+                       continue;
+               }
+               channel->last_event = s->events[s->num_events - 1];
+       }
+
+       return 0;
+}
+
+static int parse_mgt(int dmxfd)
+{
+       const enum atsc_section_tag tag = stag_atsc_master_guide;
+       struct atsc_mgt_section *mgt;
+       struct atsc_mgt_table *t;
+       int i, j, ret;
+
+       ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
**)&mgt);
+       if(0 > ret) {
+               fprintf(stderr, "%s(): error calling
atsc_scan_table()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+       if(0 == ret) {
+               fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
+               return 0;
+       }
+
+       fprintf(stdout, "MGT table:\n");
+       atsc_mgt_section_tables_for_each(mgt, t, i) {
+               struct mgt_table_name table;
+
+       for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
+               sizeof(struct mgt_table_name)); j++) {
+               if(t->table_type > mgt_tab_name_array[j].range) {
+                       continue;
+               }
+               table = mgt_tab_name_array[j];
+               if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
+                       mgt_tab_name_array[j].range) {
+                       j = -1;
+               } else {
+                       j = t->table_type - mgt_tab_name_array[j -
1].range - 1;
+                       if(0x017F == table.range) {
+                               guide.eit_pid[j] = t->table_type_PID;
+                       } else if (0x027F == table.range) {
+                               guide.ett_pid[j] = t->table_type_PID;
+                       }
+               }
+               break;
+       }
+
+               fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X,
%s", i,
+                   t->table_type, t->table_type_PID, table.string);
+               if(-1 != j) {
+                   fprintf(stdout, " %d", j);
+               }
+               fprintf(stdout, "\n");
+       }
+
+       return 0;
+}
+
+static int cleanup_guide(void)
+{
+       int i, j, k;
+
+       for(i = 0; i < guide.num_channels; i++) {
+               struct atsc_channel_info *channel = &guide.ch[i];
+
+               if(channel->title_buf.string) {
+                       free(channel->title_buf.string);
+               }
+               if(channel->msg_buf.string) {
+                       free(channel->msg_buf.string);
+               }
+               for(j = 0; j < channel->num_eits; j++) {
+                       struct atsc_eit_info *eit = &channel->eit[j];
+
+                       for(k = 0; k < eit->num_eit_sections; k++) {
+                               struct atsc_eit_section_info *section
=
+                                       &eit->section[k];
+                               if(section->num_events) {
+                                       free(section->events);
+                               }
+                       }
+                       if(k) {
+                               free(eit->section);
+                       }
+               }
+               if(j) {
+                       free(channel->eit);
+               }
+       }
+
+       return 0;
+}
+
+static int print_events(struct atsc_channel_info *channel,
+       struct atsc_eit_section_info *section)
+{
+       int m;
+       char line[256];
+
+       if(NULL == section) {
+               fprintf(stderr, "%s(): NULL pointer detected",
__FUNCTION__);
+               return -1;
+       }
+       for(m = 0; m < section->num_events; m++) {
+               struct atsc_event_info *event =
+                       section->events[m];
+
+               if(NULL == event) {
+                       continue;
+               }
+               fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
+                       event->start.tm_hour, event->start.tm_min,
+                       event->end.tm_hour, event->end.tm_min);
+               snprintf(line, event->title_len, "%s",
+                       &channel->title_buf.string[event->title_pos]);
+               line[event->title_len] = '\0';
+               fprintf(stdout, "%s\n", line);
+               if(event->msg_len) {
+                       int len = event->msg_len;
+                       int pos = event->msg_pos;
+                       size_t part;
+
+                       do {
+                               part = len > 255 ? 255 : len;
+                               snprintf(line, part, "%s",
+
&channel->msg_buf.string[pos]);
+                               line[part] = '\0';
+                               fprintf(stdout, "%s", line);
+                               len -= part;
+                               pos += part;
+                       } while(0 < len);
+                       fprintf(stdout, "\n");
+               }
+       }
+       return 0;
+}
+
+static int print_guide(void)
+{
+       int i, j, k;
+
+       fprintf(stdout, "%s\n", separator);
+       for(i = 0; i < guide.num_channels; i++) {
+               struct atsc_channel_info *channel = &guide.ch[i];
+
+               fprintf(stdout, "%d.%d  %s\n", channel->major_num,
+                       channel->minor_num, channel->short_name);
+               for(j = 0; j < channel->num_eits; j++) {
+                       struct atsc_eit_info *eit = &channel->eit[j];
+
+                       for(k = 0; k < eit->num_eit_sections; k++) {
+                               struct atsc_eit_section_info *section
=
+                                       &eit->section[k];
+                               if(print_events(channel, section)) {
+                                       fprintf(stderr, "%s(): error
calling "
+                                               "print_events()\n",
__FUNCTION__);
+                                       return -1;
+                               }
+                       }
+               }
+               fprintf(stdout, "%s\n", separator);
+       }
+
+       return 0;
+}
+
+static int open_demux(int *dmxfd)
+{
+       if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
+               fprintf(stderr, "%s(): error calling
dvbdemux_open_demux()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+       return 0;
+}
+
+static int close_demux(int dmxfd)
+{
+       if(dvbdemux_stop(dmxfd)) {
+               fprintf(stderr, "%s(): error calling
dvbdemux_stop()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+       return 0;
+}
+
+/* used other utilities as template and generalized here */
+static int atsc_scan_table(int dmxfd, uint16_t pid, enum
atsc_section_tag tag,
+       void **table_section)
+{
+       uint8_t filter[18];
+       uint8_t mask[18];
+       unsigned char sibuf[4096];
+       int size;
+       int ret;
+       struct pollfd pollfd;
+       struct section *section;
+       struct section_ext *section_ext;
+       struct atsc_section_psip *psip;
+
+       /* create a section filter for the table */
+       memset(filter, 0, sizeof(filter));
+       memset(mask, 0, sizeof(mask));
+       filter[0] = tag;
+       mask[0] = 0xFF;
+       if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1,
1)) {
+               fprintf(stderr, "%s(): error calling
atsc_scan_table()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       /* poll for data */
+       pollfd.fd = dmxfd;
+       pollfd.events = POLLIN | POLLERR |POLLPRI;
+       if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
+               if(ctrl_c) {
+                       return 0;
+               }
+               fprintf(stderr, "%s(): error calling poll()\n",
__FUNCTION__);
+               return -1;
+       }
+
+       if(0 == ret) {
+               return 0;
+       }
+
+       /* read it */
+       if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
+               fprintf(stderr, "%s(): error calling read()\n",
__FUNCTION__);
+               return -1;
+       }
+
+       /* parse section */
+       section = section_codec(sibuf, size);
+       if(NULL == section) {
+               fprintf(stderr, "%s(): error calling
section_codec()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       section_ext = section_ext_decode(section, 0);
+       if(NULL == section_ext) {
+               fprintf(stderr, "%s(): error calling
section_ext_decode()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       psip = atsc_section_psip_decode(section_ext);
+       if(NULL == psip) {
+               fprintf(stderr,
+                       "%s(): error calling
atsc_section_psip_decode()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       *table_section = table_callback[tag & 0x0F](psip);
+       if(NULL == *table_section) {
+               fprintf(stderr, "%s(): error decode table section\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       return 1;
+}
+
+int main(int argc, char *argv[])
+{
+       int i, dmxfd;
+       struct dvbfe_handle *fe;
+
+       program = argv[0];
+
+       if(1 == argc) {
+               usage();
+               exit(-1);
+       }
+
+       for( ; ; ) {
+               char c;
+
+               if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
+                       break;
+               }
+
+               switch(c) {
+               case 'a':
+                       adapter = strtoll(optarg, NULL, 0);
+                       break;
+
+               case 'f':
+                       frequency = strtol(optarg, NULL, 0);
+                       break;
+
+               case 'p':
+                       period = strtol(optarg, NULL, 0);
+                       /* each table covers 3 hours */
+                       if((3 * MAX_NUM_EVENT_TABLES) < period) {
+                               period = 3 * MAX_NUM_EVENT_TABLES;
+                       }
+                       break;
+
+               case 'm':
+                       /* just stub, so far ATSC only has VSB_8 */
+                       modulation = optarg;
+                       break;
+
+               case 't':
+                       enable_ett = 1;
+                       break;
+
+               case 'h':
+                       help();
+                       exit(0);
+
+               default:
+                       usage();
+                       exit(-1);
+               }
+       }
+
+       memset(separator, '-', sizeof(separator));
+       separator[79] = '\0';
+       memset(&guide, 0, sizeof(struct atsc_virtual_channels_info));
+       memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES *
sizeof(uint16_t));
+       memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES *
sizeof(uint16_t));
+
+       if(open_frontend(&fe)) {
+               fprintf(stderr, "%s(): error calling
open_frontend()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       if(open_demux(&dmxfd)) {
+               fprintf(stderr, "%s(): error calling open_demux()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       if(parse_stt(dmxfd)) {
+               fprintf(stderr, "%s(): error calling parse_stt()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       if(parse_mgt(dmxfd)) {
+               fprintf(stderr, "%s(): error calling parse_mgt()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       if(parse_tvct(dmxfd)) {
+               fprintf(stderr, "%s(): error calling parse_tvct()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+#ifdef ENABLE_RRT
+       if(parse_rrt(dmxfd)) {
+               fprintf(stderr, "%s(): error calling parse_rrt()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+#endif
+
+       fprintf(stdout, "receiving EIT ");
+       for(i = 0; i < guide.ch[0].num_eits; i++) {
+               if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
+                       fprintf(stderr, "%s(): error calling
parse_eit()\n",
+                               __FUNCTION__);
+                       return -1;
+               }
+       }
+       fprintf(stdout, "\n");
+
+       old_handler = signal(SIGINT, int_handler);
+       if(enable_ett) {
+               fprintf(stdout, "receiving ETT ");
+               for(i = 0; i < guide.ch[0].num_eits; i++) {
+                       if(0xFFFF != guide.ett_pid[i]) {
+                               if(parse_ett(dmxfd, i,
guide.ett_pid[i])) {
+                                       fprintf(stderr, "%s(): error
calling "
+                                               "parse_eit()\n",
__FUNCTION__);
+                                       return -1;
+                               }
+                       }
+                       if(ctrl_c) {
+                               break;
+                       }
+               }
+               fprintf(stdout, "\n");
+       }
+       signal(SIGINT, old_handler);
+
+       if(print_guide()) {
+               fprintf(stderr, "%s(): error calling print_guide()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       if(cleanup_guide()) {
+               fprintf(stderr, "%s(): error calling
cleanup_guide()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       if(close_demux(dmxfd)) {
+               fprintf(stderr, "%s(): error calling close_demux()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       if(close_frontend(fe)) {
+               fprintf(stderr, "%s(): error calling close_demux()\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       return 0;
+}
diff -uprN dvb-apps/util/atsc_epg/Makefile
dvb-apps_new/util/atsc_epg/Makefile
--- dvb-apps/util/atsc_epg/Makefile     1969-12-31 18:00:00.000000000
-0600
+++ dvb-apps_new/util/atsc_epg/Makefile 2009-06-18 20:11:58.362985962
-0500
@@ -0,0 +1,16 @@
+# Makefile for linuxtv.org dvb-apps/util/atsc_epg
+
+binaries = atsc_epg
+
+inst_bin = $(binaries)
+
+CPPFLAGS += -I../../lib -std=c99 -D_POSIX_SOURCE
+#LDFLAGS  += -static -L../../lib/libdvbapi -L../../lib/libucsi
+LDFLAGS  += -L../../lib/libdvbapi -L../../lib/libucsi
+LDLIBS   += -ldvbapi -lucsi
+
+.PHONY: all
+
+all: $(binaries)
+
+include ../../Make.rules
diff -uprN dvb-apps/util/atsc_epg/README dvb-apps_new/util/atsc_epg/README
--- dvb-apps/util/atsc_epg/README       1969-12-31 18:00:00.000000000 -0600
+++ dvb-apps_new/util/atsc_epg/README   2009-06-18 20:33:47.836924378 -0500
@@ -0,0 +1,12 @@
+Hi there,
+
+atsc_epg is a small utility for obtaining information such as programs, EPG
+(electronic program guide) from an ATSC channel.
+
+Pulling the detailed information, i.e., option '-t', may take fairly long
+time, or never ending, which is a bug of the PSIP generator. Ctrl+C can be
+used to abort and the received parts will be printed.
+
+Enjoy,
+Yufei
+
diff -uprN dvb-apps/util/Makefile dvb-apps_new/util/Makefile
--- dvb-apps/util/Makefile      2009-06-18 19:43:30.034986539 -0500
+++ dvb-apps_new/util/Makefile  2009-06-18 20:11:41.169986806 -0500
@@ -3,6 +3,7 @@
 .PHONY: all clean install

 all clean install:
+       $(MAKE) -C atsc_epg $@
        $(MAKE) -C av7110_loadkeys $@
        $(MAKE) -C dib3000-watch $@
        $(MAKE) -C dst-utils $@

-- 
Even uttering "HI" or "HAO" is offensive, sometime, somewhere. Reader
discretion is advised.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-19  1:39         ` Yufei Yuan
@ 2009-06-20  0:41           ` hermann pitton
  2009-06-20  1:00             ` Yufei Yuan
       [not found]           ` <ccdf9f470906181855m2d6c471cm12afea3f228fd57c@mail.gmail.com>
  1 sibling, 1 reply; 22+ messages in thread
From: hermann pitton @ 2009-06-20  0:41 UTC (permalink / raw)
  To: Yufei Yuan; +Cc: Manu Abraham, Linux Media Mailing List


Am Donnerstag, den 18.06.2009, 20:39 -0500 schrieb Yufei Yuan:
> This one is about the utility itself. I do apologize for the length
> here as "inline" patch is preferred according to the guide and I don't
> have any public online storage. Please let me know if this causes any
> inconvenience.
> 
> Signed-off-by: Yufei Yuan <yfyuan@gmail.com>
> 
> diff -uprN dvb-apps/util/atsc_epg/atsc_epg.c
> dvb-apps_new/util/atsc_epg/atsc_epg.c
> --- dvb-apps/util/atsc_epg/atsc_epg.c   1969-12-31 18:00:00.000000000
> -0600
> +++ dvb-apps_new/util/atsc_epg/atsc_epg.c       2009-06-18
> 20:17:24.527925142 -0500
> @@ -0,0 +1,1249 @@
> +/*
> + * atsc_epg utility
> + *
> + * Copyright (C) 2009 Yufei Yuan <yfyuan@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <time.h>
> +#include <signal.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <sys/ioctl.h>
> +#include <sys/poll.h>
> +#include <errno.h>
> +#include <getopt.h>
> +#include <stdarg.h>
> +#include <libdvbapi/dvbfe.h>
> +#include <libdvbapi/dvbdemux.h>
> +#include <libucsi/dvb/section.h>
> +#include <libucsi/atsc/section.h>
> +#include <libucsi/atsc/types.h>
> +
> +#define TIMEOUT                                60
> +#define RRT_TIMEOUT                    60
> +#define MAX_NUM_EVENT_TABLES           128
> +#define TITLE_BUFFER_LEN               4096
> +#define MESSAGE_BUFFER_LEN             (16 * 1024)
> +#define MAX_NUM_CHANNELS               16
> +#define MAX_NUM_EVENTS_PER_CHANNEL     (4 * 24 * 7)
> +
> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum
> atsc_section_tag tag,
> +       void **table_section);
> +
> +static const char *program;
> +static int adapter = 0;
> +static int period = 12; /* hours */
> +static int frequency;
> +static int enable_ett = 0;
> +static int ctrl_c = 0;
> +static const char *modulation = NULL;
> +static char separator[80];
> +void (*old_handler)(int);
> +
> +struct atsc_string_buffer {
> +       int buf_len;
> +       int buf_pos;
> +       char *string;
> +};
> +
> +struct atsc_event_info {
> +       uint16_t id;
> +       struct tm start;
> +       struct tm end;
> +       int title_pos;
> +       int title_len;
> +       int msg_pos;
> +       int msg_len;
> +};
> +
> +struct atsc_eit_section_info {
> +       uint8_t section_num;
> +       uint8_t num_events;
> +       uint8_t num_etms;
> +       uint8_t num_received_etms;
> +       struct atsc_event_info **events;
> +};
> +
> +struct atsc_eit_info {
> +       int num_eit_sections;
> +       struct atsc_eit_section_info *section;
> +};
> +
> +struct atsc_channel_info {
> +       uint8_t num_eits;
> +       uint8_t service_type;
> +       char short_name[8];
> +       uint16_t major_num;
> +       uint16_t minor_num;
> +       uint16_t tsid;
> +       uint16_t prog_num;
> +       uint16_t src_id;
> +       struct atsc_eit_info *eit;
> +       struct atsc_event_info *last_event;
> +       int event_info_index;
> +       struct atsc_event_info e[MAX_NUM_EVENTS_PER_CHANNEL];
> +       struct atsc_string_buffer title_buf;
> +       struct atsc_string_buffer msg_buf;
> +};
> +
> +struct atsc_virtual_channels_info {
> +       int num_channels;
> +       uint16_t eit_pid[MAX_NUM_EVENT_TABLES];
> +       uint16_t ett_pid[MAX_NUM_EVENT_TABLES];
> +       struct atsc_channel_info ch[MAX_NUM_CHANNELS];
> +} guide;
> +
> +struct mgt_table_name {
> +       uint16_t range;
> +       const char *string;
> +};
> +
> +struct mgt_table_name mgt_tab_name_array[] = {
> +       {0x0000, "terrestrial VCT with current_next_indictor=1"},
> +       {0x0001, "terrestrial VCT with current_next_indictor=0"},
> +       {0x0002, "cable VCT with current_next_indictor=1"},
> +       {0x0003, "cable VCT with current_next_indictor=0"},
> +       {0x0004, "channel ETT"},
> +       {0x0005, "DCCSCT"},
> +       {0x00FF, "reserved for future ATSC use"},
> +       {0x017F, "EIT"},
> +       {0x01FF, "reserved for future ATSC use"},
> +       {0x027F, "event ETT"},
> +       {0x02FF, "reserved for future ATSC use"}, /* FIXME */
> +       {0x03FF, "RRT with rating region"},
> +       {0x0FFF, "user private"},
> +       {0x13FF, "reserved for future ATSC use"},
> +       {0x14FF, "DCCT with dcc_id"},
> +       {0xFFFF, "reserved for future ATSC use"}
> +};
> +
> +const char *channel_modulation_mode[] = {
> +       "",
> +       "analog",
> +       "SCTE mode 1",
> +       "SCTE mode 2",
> +       "ATSC 8VSB",
> +       "ATSC 16VSB"
> +};
> +
> +const char *channel_service_type[] = {
> +       "",
> +       "analog TV",
> +       "ATSC digital TV",
> +       "ATSC audio",
> +       "ATSC data-only"
> +};
> +
> +void *(*table_callback[16])(struct atsc_section_psip *) =
> +{
> +       NULL, NULL, NULL, NULL, NULL, NULL, NULL,
> +       (void *(*)(struct atsc_section_psip *))atsc_mgt_section_codec,
> +       (void *(*)(struct atsc_section_psip
> *))atsc_tvct_section_codec,
> +       (void *(*)(struct atsc_section_psip
> *))atsc_cvct_section_codec,
> +       (void *(*)(struct atsc_section_psip *))atsc_rrt_section_codec,
> +       (void *(*)(struct atsc_section_psip *))atsc_eit_section_codec,
> +       (void *(*)(struct atsc_section_psip *))atsc_ett_section_codec,
> +       (void *(*)(struct atsc_section_psip *))atsc_stt_section_codec,
> +       NULL, NULL
> +};
> +
> +static void int_handler(int sig_num)
> +{
> +       if(SIGINT != sig_num) {
> +               return;
> +       }
> +       ctrl_c = 1;
> +}
> +
> +/* shamelessly stolen from dvbsnoop, but almost not modified */
> +static uint32_t get_bits(const uint8_t *buf, int startbit, int
> bitlen)
> +{
> +       const uint8_t *b;
> +       uint32_t mask,tmp_long;
> +       int bitHigh,i;
> +
> +       b = &buf[startbit / 8];
> +       startbit %= 8;
> +
> +       bitHigh = 8;
> +       tmp_long = b[0];
> +       for (i = 0; i < ((bitlen-1) >> 3); i++) {
> +               tmp_long <<= 8;
> +               tmp_long  |= b[i+1];
> +               bitHigh   += 8;
> +       }
> +
> +       startbit = bitHigh - startbit - bitlen;
> +       tmp_long = tmp_long >> startbit;
> +       mask     = (1ULL << bitlen) - 1;
> +       return tmp_long & mask;
> +}
> +
> +static void usage(void)
> +{
> +       fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p
> <period>]"
> +               " [-m <modulation>] [-t] [-h]\n", program);
> +}
> +
> +static void help(void)
> +{
> +       fprintf(stderr,
> +       "\nhelp:\n"
> +       "%s [-a <n>] -f <frequency> [-p <period>] [-m <modulation>]
> [-t] [-h]\n"
> +       "  -a: adapter index to use, (default 0)\n"
> +       "  -f: tuning frequency\n"
> +       "  -p: period in hours, (default 12)\n"
> +       "  -m: modulation ATSC vsb_8|vsb_16 (default vsb_8)\n"
> +       "  -t: enable ETT to receive program details, if available\n"
> +       "  -h: display this message\n", program);
> +}
> +
> +static int close_frontend(struct dvbfe_handle *fe)
> +{
> +       if(NULL == fe) {
> +               fprintf(stderr, "%s(): NULL pointer detected\n",
> __FUNCTION__);
> +       }
> +
> +       dvbfe_close(fe);
> +
> +       return 0;
> +}
> +
> +static int open_frontend(struct dvbfe_handle **fe)
> +{
> +       struct dvbfe_info fe_info;
> +
> +       if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
> +               fprintf(stderr, "%s(): error calling dvbfe_open()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +       dvbfe_get_info(*fe, 0, &fe_info,
> DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
> +       if(DVBFE_TYPE_ATSC != fe_info.type) {
> +               fprintf(stderr, "%s(): only ATSC frontend supported
> currently\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +       fe_info.feparams.frequency = frequency;
> +       fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
> +       fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
> +       fprintf(stdout, "tuning to %d Hz, please wait...\n",
> frequency);
> +       if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
> +               fprintf(stderr, "%s(): cannot lock to %d Hz in %d
> seconds\n",
> +                       __FUNCTION__, frequency, TIMEOUT);
> +               return -1;
> +       }
> +       fprintf(stdout, "tuner locked.\n");
> +
> +       return 0;
> +}
> +
> +#if ENABLE_RRT
> +/* this is untested as since this part of the library is broken */
> +static int parse_rrt(int dmxfd)
> +{
> +       const enum atsc_section_tag tag = stag_atsc_rating_region;
> +       struct atsc_rrt_section *rrt;
> +       struct atsc_text *region_name;
> +       struct atsc_text_string *atsc_str;
> +       int i, j, ret;
> +
> +       i = 0;
> +       fprintf(stdout, "waiting for RRT: ");
> +       fflush(stdout);
> +       while(i < RRT_TIMEOUT) {
> +               ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
> **)&rrt);
> +               if(0 > ret) {
> +                       fprintf(stderr, "%s(): error calling
> atsc_scan_table()\n",
> +                               __FUNCTION__);
> +                       return -1;
> +               }
> +               if(0 == ret) {
> +                       if(RRT_TIMEOUT > i) {
> +                               fprintf(stdout, ".");
> +                               fflush(stdout);
> +                       } else {
> +                               fprintf(stdout, "\nno RRT in %d
> seconds\n",
> +                                       RRT_TIMEOUT);
> +                               return 0;
> +                       }
> +                       i += TIMEOUT;
> +               } else {
> +                       fprintf(stdout, "\n");
> +                       fflush(stdout);
> +                       break;
> +               }
> +       }
> +
> +       region_name = atsc_rrt_section_rating_region_name_text(rrt);
> +       atsc_text_strings_for_each(region_name, atsc_str, i) {
> +               struct atsc_text_string_segment *seg;
> +
> +               atsc_text_string_segments_for_each(atsc_str, seg, j) {
> +                       const char *c;
> +                       int k;
> +                       if(seg->mode < 0x3E) {
> +                               fprintf(stderr, "%s(): text mode of
> 0x%02X "
> +                                       "not supported yet\n",
> +                                       __FUNCTION__, seg->mode);
> +                               return -1;
> +                       }
> +                       c = (const char
> *)atsc_text_string_segment_bytes(seg);
> +                       for(k = 0; k < seg->number_bytes; k++) {
> +                               fprintf(stdout, "%c", c[k]);
> +                       }
> +               }
> +       }
> +
> +       return 0;
> +}
> +#endif
> +
> +static int parse_stt(int dmxfd)
> +{
> +       const enum atsc_section_tag tag = stag_atsc_system_time;
> +       const struct atsc_stt_section *stt;
> +       time_t rx_time;
> +       time_t sys_time;
> +       int ret;
> +
> +       ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
> **)&stt);
> +       if(0 > ret) {
> +               fprintf(stderr, "%s(): error calling
> atsc_scan_table()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +       if(0 == ret) {
> +               fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
> +               return 0;
> +       }
> +
> +       rx_time = atsctime_to_unixtime(stt->system_time);
> +       time(&sys_time);
> +       fprintf(stdout, "system time: %s", ctime(&sys_time));
> +       fprintf(stdout, "TS STT time: %s", ctime(&rx_time));
> +
> +       return 0;
> +}
> +
> +static int parse_tvct(int dmxfd)
> +{
> +       int num_sections;
> +       uint32_t section_pattern;
> +       const enum atsc_section_tag tag =
> stag_atsc_terrestrial_virtual_channel;
> +       struct atsc_tvct_section *tvct;
> +       struct atsc_tvct_channel *ch;
> +       struct atsc_channel_info *curr_info;
> +       int i, k, ret;
> +
> +       section_pattern = 0;
> +       num_sections = -1;
> +
> +       do {
> +               ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
> **)&tvct);
> +               if(0 > ret) {
> +                       fprintf(stderr, "%s(): error calling
> atsc_scan_table()\n",
> +                       __FUNCTION__);
> +                       return -1;
> +               }
> +               if(0 == ret) {
> +                       fprintf(stdout, "no TVCT in %d seconds\n",
> TIMEOUT);
> +                       return 0;
> +               }
> +
> +               if(-1 == num_sections) {
> +                       num_sections = 1 +
> tvct->head.ext_head.last_section_number;
> +                       if(32 < num_sections) {
> +                               fprintf(stderr, "%s(): no support yet
> for "
> +                                       "tables having more than 32
> sections\n",
> +                                       __FUNCTION__);
> +                               return -1;
> +                       }
> +               } else {
> +                       if(num_sections !=
> +                               1 +
> tvct->head.ext_head.last_section_number) {
> +                               fprintf(stderr,
> +                                       "%s(): last section number
> does not match\n",
> +                                       __FUNCTION__);
> +                               return -1;
> +                       }
> +               }
> +               if(section_pattern & (1 <<
> tvct->head.ext_head.section_number)) {
> +                       continue;
> +               }
> +               section_pattern |= 1 <<
> tvct->head.ext_head.section_number;
> +
> +               if(MAX_NUM_CHANNELS < guide.num_channels +
> +                       tvct->num_channels_in_section) {
> +                       fprintf(stderr, "%s(): no support for more
> than %d "
> +                               "virtual channels in a pyhsical
> channel\n",
> +                               __FUNCTION__, MAX_NUM_CHANNELS);
> +                       return -1;
> +               }
> +               curr_info = &guide.ch[guide.num_channels];
> +               guide.num_channels += tvct->num_channels_in_section;
> +
> +       atsc_tvct_section_channels_for_each(tvct, ch, i) {
> +               /* initialize the curr_info structure */
> +               /* each EIT covers 3 hours */
> +               curr_info->num_eits = (period / 3) + !!(period % 3);
> +               while (curr_info->num_eits &&
> +                       (0xFFFF == guide.eit_pid[curr_info->num_eits -
> 1])) {
> +                       curr_info->num_eits -= 1;
> +               }
> +               if(curr_info->eit) {
> +                       fprintf(stderr, "%s(): non-NULL pointer
> detected "
> +                               "during initialization",
> __FUNCTION__);
> +                       return -1;
> +               }
> +               if(NULL == (curr_info->eit =
> calloc(curr_info->num_eits,
> +                       sizeof(struct atsc_eit_info)))) {
> +                       fprintf(stderr, "%s(): error calling
> calloc()\n",
> +                               __FUNCTION__);
> +                       return -1;
> +               }
> +               if(NULL == (curr_info->title_buf.string =
> calloc(TITLE_BUFFER_LEN,
> +                       sizeof(char)))) {
> +                       fprintf(stderr, "%s(): error calling
> calloc()\n",
> +                               __FUNCTION__);
> +                       return -1;
> +               }
> +               curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
> +               curr_info->title_buf.buf_pos = 0;
> +
> +               if(NULL == (curr_info->msg_buf.string =
> calloc(MESSAGE_BUFFER_LEN,
> +                       sizeof(char)))) {
> +                       fprintf(stderr, "%s(): error calling
> calloc()\n",
> +                               __FUNCTION__);
> +                       return -1;
> +               }
> +               curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
> +               curr_info->msg_buf.buf_pos = 0;
> +
> +               for(k = 0; k < 7; k++) {
> +                       curr_info->short_name[k] =
> +                               get_bits((const uint8_t
> *)ch->short_name,
> +                               k * 16, 16);
> +               }
> +               curr_info->service_type = ch->service_type;
> +               curr_info->major_num = ch->major_channel_number;
> +               curr_info->minor_num = ch->minor_channel_number;
> +               curr_info->tsid = ch->channel_TSID;
> +               curr_info->prog_num = ch->program_number;
> +               curr_info->src_id = ch->source_id;
> +               curr_info++;
> +               }
> +       } while(section_pattern != (uint32_t)((1 << num_sections) -
> 1));
> +
> +       return 0;
> +}
> +
> +static int match_event(struct atsc_eit_info *eit, uint16_t event_id,
> +       struct atsc_event_info **event, uint8_t *curr_index)
> +{
> +       int j, k;
> +       struct atsc_eit_section_info *section;
> +
> +       if(NULL == eit || NULL == event || NULL == curr_index) {
> +               fprintf(stderr, "%s(): NULL pointer detected\n",
> __FUNCTION__);
> +               return -1;
> +       }
> +
> +       for(j = 0; j < eit->num_eit_sections; j++) {
> +               section = &eit->section[j];
> +
> +               for(k = 0; k < section->num_events; k++) {
> +                       if(section->events[k] &&
> section->events[k]->id ==
> +                               event_id) {
> +                               *event = section->events[k];
> +                               break;
> +                       }
> +               }
> +               if(*event) {
> +                       *curr_index = j;
> +                       break;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int parse_message(struct atsc_channel_info *channel,
> +       struct atsc_ett_section *ett, struct atsc_event_info *event)
> +{
> +       int i, j;
> +       struct atsc_text *text;
> +       struct atsc_text_string *str;
> +
> +       if(NULL == ett || NULL == event || NULL == channel) {
> +               fprintf(stderr, "%s(): NULL pointer detected\n",
> __FUNCTION__);
> +               return -1;
> +       }
> +
> +       text = atsc_ett_section_extended_text_message(ett);
> +       atsc_text_strings_for_each(text, str, i) {
> +               struct atsc_text_string_segment *seg;
> +
> +               atsc_text_string_segments_for_each(str, seg, j) {
> +                       event->msg_pos = channel->msg_buf.buf_pos;
> +                       if(0 > atsc_text_segment_decode(seg,
> +                               (uint8_t **)&channel->msg_buf.string,
> +                               (size_t *)&channel->msg_buf.buf_len,
> +                               (size_t *)&channel->msg_buf.buf_pos))
> {
> +                               fprintf(stderr, "%s(): error calling "
> +
> "atsc_text_segment_decode()\n",
> +                                       __FUNCTION__);
> +                               return -1;
> +                       }
> +                       event->msg_len = 1 + channel->msg_buf.buf_pos
> -
> +                               event->msg_pos;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int parse_ett(int dmxfd, int index, uint16_t pid)
> +{
> +       uint8_t curr_index;
> +       uint32_t section_pattern;
> +       const enum atsc_section_tag tag = stag_atsc_extended_text;
> +       struct atsc_eit_info *eit;
> +       struct atsc_ett_section *ett;
> +       struct atsc_channel_info *channel;
> +       struct atsc_event_info *event;
> +       struct atsc_eit_section_info *section;
> +       uint16_t source_id, event_id;
> +       int c, ret;
> +
> +       if(0xFFFF == guide.ett_pid[index]) {
> +               return 0;
> +       }
> +
> +       for(c = 0; c < guide.num_channels; c++) {
> +               channel = &guide.ch[c];
> +               eit = &channel->eit[index];
> +
> +               section_pattern = 0;
> +               while(section_pattern !=
> +                       (uint32_t)((1 << eit->num_eit_sections) - 1))
> {
> +                       if(ctrl_c) {
> +                               return 0;
> +                       }
> +                       ret = atsc_scan_table(dmxfd, pid, tag, (void
> **)&ett);
> +                       fprintf(stdout, ".");
> +                       fflush(stdout);
> +                       if(0 > ret) {
> +                               fprintf(stderr, "%s(): error calling "
> +                                       "atsc_scan_table()\n",
> __FUNCTION__);
> +                               return -1;
> +                       }
> +                       if(0 == ret) {
> +                               fprintf(stdout, "no ETT %d in %d
> seconds\n",
> +                                       index, TIMEOUT);
> +                               return 0;
> +                       }
> +
> +                       source_id = ett->ETM_source_id;
> +                       event_id = ett->ETM_sub_id;
> +                       if(source_id != channel->src_id) {
> +                               continue;
> +                       }
> +
> +                       event = NULL;
> +                       if(match_event(eit, event_id, &event,
> &curr_index)) {
> +                               fprintf(stderr, "%s(): error calling "
> +                                       "match_event()\n",
> __FUNCTION__);
> +                               return -1;
> +                       }
> +                       if(NULL == event) {
> +                               continue;
> +                       }
> +                       if(section_pattern & (1 << curr_index)) {
> +                               /* the section has been filled, so
> skip,
> +                                * not consider version yet
> +                                */
> +                               continue;
> +                       }
> +                       if(event->msg_len) {
> +                               /* the message has been filled */
> +                               continue;
> +                       }
> +
> +                       if(parse_message(channel, ett, event)) {
> +                               fprintf(stderr, "%s(): error calling "
> +                                       "parse_message()\n",
> __FUNCTION__);
> +                               return -1;
> +                       }
> +                       section = &eit->section[curr_index];
> +                       if(++section->num_received_etms ==
> section->num_etms) {
> +                               section_pattern |= 1 << curr_index;
> +                       }
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int parse_events(struct atsc_channel_info *curr_info,
> +       struct atsc_eit_section *eit, struct atsc_eit_section_info
> *section)
> +{
> +       int i, j, k;
> +       struct atsc_eit_event *e;
> +       time_t start_time, end_time;
> +
> +       if(NULL == curr_info || NULL == eit) {
> +               fprintf(stderr, "%s(): NULL pointer detected\n",
> __FUNCTION__);
> +               return -1;
> +       }
> +
> +       atsc_eit_section_events_for_each(eit, e, i) {
> +               struct atsc_text *title;
> +               struct atsc_text_string *str;
> +               struct atsc_event_info *e_info =
> +                       &curr_info->e[curr_info->event_info_index];
> +
> +               if(0 == i && curr_info->last_event) {
> +                       if(e->event_id == curr_info->last_event->id) {
> +                               section->events[i] = NULL;
> +                               /* skip if it's the same event
> spanning
> +                                * over sections
> +                                */
> +                               continue;
> +                       }
> +               }
> +               curr_info->event_info_index += 1;
> +               section->events[i] = e_info;
> +               e_info->id = e->event_id;
> +               start_time = atsctime_to_unixtime(e->start_time);
> +               end_time = start_time + e->length_in_seconds;
> +               localtime_r(&start_time, &e_info->start);
> +               localtime_r(&end_time, &e_info->end);
> +               if(0 != e->ETM_location && 3 != e->ETM_location) {
> +                       /* FIXME assume 1 and 2 is interchangable as
> of now */
> +                       section->num_etms++;
> +               }
> +
> +               title = atsc_eit_event_name_title_text(e);
> +               atsc_text_strings_for_each(title, str, j) {
> +                       struct atsc_text_string_segment *seg;
> +
> +                       atsc_text_string_segments_for_each(str, seg,
> k) {
> +                               e_info->title_pos =
> curr_info->title_buf.buf_pos;
> +                               if(0 > atsc_text_segment_decode(seg,
> +                                       (uint8_t
> **)&curr_info->title_buf.string,
> +                                       (size_t
> *)&curr_info->title_buf.buf_len,
> +                                       (size_t
> *)&curr_info->title_buf.buf_pos)) {
> +                                       fprintf(stderr, "%s(): error
> calling "
> +
> "atsc_text_segment_decode()\n",
> +                                               __FUNCTION__);
> +                                       return -1;
> +                               }
> +                               e_info->title_len =
> curr_info->title_buf.buf_pos -
> +                                       e_info->title_pos + 1;
> +                       }
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int parse_eit(int dmxfd, int index, uint16_t pid)
> +{
> +       int num_sections;
> +       uint8_t section_num;
> +       uint8_t curr_channel_index;
> +       uint32_t section_pattern;
> +       const enum atsc_section_tag tag = stag_atsc_event_information;
> +       struct atsc_eit_section *eit;
> +       struct atsc_channel_info *curr_info;
> +       struct atsc_eit_info *eit_info;
> +       struct atsc_eit_section_info *section;
> +       uint16_t source_id;
> +       uint32_t eit_instance_pattern = 0;
> +       int i, k, ret;
> +
> +       while(eit_instance_pattern !=
> +               (uint32_t)((1 << guide.num_channels) - 1)) {
> +               source_id = 0xFFFF;
> +               section_pattern = 0;
> +               num_sections = -1;
> +
> +               do {
> +                       ret = atsc_scan_table(dmxfd, pid, tag, (void
> **)&eit);
> +                       fprintf(stdout, ".");
> +                       fflush(stdout);
> +                       if(0 > ret) {
> +                               fprintf(stderr, "%s(): error calling "
> +                                       "atsc_scan_table()\n",
> __FUNCTION__);
> +                               return -1;
> +                       }
> +                       if(0 == ret) {
> +                               fprintf(stdout, "no EIT %d in %d
> seconds\n",
> +                                       index, TIMEOUT);
> +                               return 0;
> +                       }
> +
> +                       if(0xFFFF == source_id) {
> +                       source_id = atsc_eit_section_source_id(eit);
> +                       for(k = 0; k < guide.num_channels; k++) {
> +                               if(source_id == guide.ch[k].src_id) {
> +                                       curr_info = &guide.ch[k];
> +                                       curr_channel_index = k;
> +                                       if(0 == index) {
> +                                               curr_info->last_event
> = NULL;
> +                                       }
> +                                       break;
> +                               }
> +                       }
> +                       if(k == guide.num_channels) {
> +                               fprintf(stderr, "%s(): cannot find
> source_id "
> +                                       "0x%04X in the EIT\n",
> +                                       __FUNCTION__, source_id);
> +                               return -1;
> +                       }
> +                       } else {
> +                               if(source_id !=
> +
> atsc_eit_section_source_id(eit)) {
> +                                       continue;
> +                               }
> +                       }
> +                       if(eit_instance_pattern & (1 <<
> curr_channel_index)) {
> +                               /* we have received this instance,
> +                                * so quit quick
> +                                */
> +                               break;
> +                       }
> +
> +                       if(-1 == num_sections) {
> +                               num_sections = 1 +
> +
> eit->head.ext_head.last_section_number;
> +                               if(32 < num_sections) {
> +                                       fprintf(stderr,
> +                                               "%s(): no support yet
> for "
> +                                               "tables having more
> than "
> +                                               "32 sections\n",
> __FUNCTION__);
> +                                       return -1;
> +                               }
> +                       } else {
> +                               if(num_sections != 1 +
> +
> eit->head.ext_head.last_section_number) {
> +                                       fprintf(stderr,
> +                                               "%s(): last section
> number "
> +                                               "does not match\n",
> +                                               __FUNCTION__);
> +                                       return -1;
> +                               }
> +                       }
> +                       if(section_pattern &
> +                               (1 <<
> eit->head.ext_head.section_number)) {
> +                               continue;
> +                       }
> +                       section_pattern |= 1 <<
> eit->head.ext_head.section_number;
> +
> +                       eit_info = &curr_info->eit[index];
> +                       if(NULL == (eit_info->section =
> +                               realloc(eit_info->section,
> +                               (eit_info->num_eit_sections + 1) *
> +                               sizeof(struct
> atsc_eit_section_info)))) {
> +                               fprintf(stderr,
> +                                       "%s(): error calling
> realloc()\n",
> +                                       __FUNCTION__);
> +                               return -1;
> +                       }
> +                       section_num =
> eit->head.ext_head.section_number;
> +                       if(0 == eit_info->num_eit_sections) {
> +                               eit_info->num_eit_sections = 1;
> +                               section = eit_info->section;
> +                       } else {
> +                               /* have to sort it into section order
> +                                * (temporal order)
> +                                */
> +                               for(i = 0; i <
> eit_info->num_eit_sections; i++) {
> +
> if(eit_info->section[i].section_num >
> +                                               section_num) {
> +                                               break;
> +                                       }
> +                               }
> +                               memmove(&eit_info->section[i + 1],
> +                                       &eit_info->section[i],
> +                                       (eit_info->num_eit_sections -
> i) *
> +                                       sizeof(struct
> atsc_eit_section_info));
> +                               section = &eit_info->section[i - 1];
> +                               section = &eit_info->section[i];
> +                               eit_info->num_eit_sections += 1;
> +                       }
> +
> +                       section->section_num = section_num;
> +                       section->num_events =
> eit->num_events_in_section;
> +                       section->num_etms = 0;
> +                       section->num_received_etms = 0;
> +                       if(NULL == (section->events =
> calloc(section->num_events,
> +                               sizeof(struct atsc_event_info *)))) {
> +                               fprintf(stderr, "%s(): error calling
> calloc()\n",
> +                                       __FUNCTION__);
> +                               return -1;
> +                       }
> +                       if(parse_events(curr_info, eit, section)) {
> +                               fprintf(stderr, "%s(): error calling "
> +                                       "parse_events()\n",
> __FUNCTION__);
> +                               return -1;
> +                       }
> +               } while(section_pattern != (uint32_t)((1 <<
> num_sections) - 1));
> +               eit_instance_pattern |= 1 << curr_channel_index;
> +       }
> +
> +       for(i = 0; i < guide.num_channels; i++) {
> +               struct atsc_channel_info *channel = &guide.ch[i];
> +               struct atsc_eit_info *ei = &channel->eit[index];
> +               struct atsc_eit_section_info *s;
> +
> +               if(0 == ei->num_eit_sections) {
> +                       channel->last_event = NULL;
> +                       continue;
> +               }
> +               s = &ei->section[ei->num_eit_sections - 1];
> +               /* BUG: it's incorrect when last section has no event
> */
> +               if(0 == s->num_events) {
> +                       channel->last_event = NULL;
> +                       continue;
> +               }
> +               channel->last_event = s->events[s->num_events - 1];
> +       }
> +
> +       return 0;
> +}
> +
> +static int parse_mgt(int dmxfd)
> +{
> +       const enum atsc_section_tag tag = stag_atsc_master_guide;
> +       struct atsc_mgt_section *mgt;
> +       struct atsc_mgt_table *t;
> +       int i, j, ret;
> +
> +       ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
> **)&mgt);
> +       if(0 > ret) {
> +               fprintf(stderr, "%s(): error calling
> atsc_scan_table()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +       if(0 == ret) {
> +               fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
> +               return 0;
> +       }
> +
> +       fprintf(stdout, "MGT table:\n");
> +       atsc_mgt_section_tables_for_each(mgt, t, i) {
> +               struct mgt_table_name table;
> +
> +       for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
> +               sizeof(struct mgt_table_name)); j++) {
> +               if(t->table_type > mgt_tab_name_array[j].range) {
> +                       continue;
> +               }
> +               table = mgt_tab_name_array[j];
> +               if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
> +                       mgt_tab_name_array[j].range) {
> +                       j = -1;
> +               } else {
> +                       j = t->table_type - mgt_tab_name_array[j -
> 1].range - 1;
> +                       if(0x017F == table.range) {
> +                               guide.eit_pid[j] = t->table_type_PID;
> +                       } else if (0x027F == table.range) {
> +                               guide.ett_pid[j] = t->table_type_PID;
> +                       }
> +               }
> +               break;
> +       }
> +
> +               fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X,
> %s", i,
> +                   t->table_type, t->table_type_PID, table.string);
> +               if(-1 != j) {
> +                   fprintf(stdout, " %d", j);
> +               }
> +               fprintf(stdout, "\n");
> +       }
> +
> +       return 0;
> +}
> +
> +static int cleanup_guide(void)
> +{
> +       int i, j, k;
> +
> +       for(i = 0; i < guide.num_channels; i++) {
> +               struct atsc_channel_info *channel = &guide.ch[i];
> +
> +               if(channel->title_buf.string) {
> +                       free(channel->title_buf.string);
> +               }
> +               if(channel->msg_buf.string) {
> +                       free(channel->msg_buf.string);
> +               }
> +               for(j = 0; j < channel->num_eits; j++) {
> +                       struct atsc_eit_info *eit = &channel->eit[j];
> +
> +                       for(k = 0; k < eit->num_eit_sections; k++) {
> +                               struct atsc_eit_section_info *section
> =
> +                                       &eit->section[k];
> +                               if(section->num_events) {
> +                                       free(section->events);
> +                               }
> +                       }
> +                       if(k) {
> +                               free(eit->section);
> +                       }
> +               }
> +               if(j) {
> +                       free(channel->eit);
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int print_events(struct atsc_channel_info *channel,
> +       struct atsc_eit_section_info *section)
> +{
> +       int m;
> +       char line[256];
> +
> +       if(NULL == section) {
> +               fprintf(stderr, "%s(): NULL pointer detected",
> __FUNCTION__);
> +               return -1;
> +       }
> +       for(m = 0; m < section->num_events; m++) {
> +               struct atsc_event_info *event =
> +                       section->events[m];
> +
> +               if(NULL == event) {
> +                       continue;
> +               }
> +               fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
> +                       event->start.tm_hour, event->start.tm_min,
> +                       event->end.tm_hour, event->end.tm_min);
> +               snprintf(line, event->title_len, "%s",
> +                       &channel->title_buf.string[event->title_pos]);
> +               line[event->title_len] = '\0';
> +               fprintf(stdout, "%s\n", line);
> +               if(event->msg_len) {
> +                       int len = event->msg_len;
> +                       int pos = event->msg_pos;
> +                       size_t part;
> +
> +                       do {
> +                               part = len > 255 ? 255 : len;
> +                               snprintf(line, part, "%s",
> +
> &channel->msg_buf.string[pos]);
> +                               line[part] = '\0';
> +                               fprintf(stdout, "%s", line);
> +                               len -= part;
> +                               pos += part;
> +                       } while(0 < len);
> +                       fprintf(stdout, "\n");
> +               }
> +       }
> +       return 0;
> +}
> +
> +static int print_guide(void)
> +{
> +       int i, j, k;
> +
> +       fprintf(stdout, "%s\n", separator);
> +       for(i = 0; i < guide.num_channels; i++) {
> +               struct atsc_channel_info *channel = &guide.ch[i];
> +
> +               fprintf(stdout, "%d.%d  %s\n", channel->major_num,
> +                       channel->minor_num, channel->short_name);
> +               for(j = 0; j < channel->num_eits; j++) {
> +                       struct atsc_eit_info *eit = &channel->eit[j];
> +
> +                       for(k = 0; k < eit->num_eit_sections; k++) {
> +                               struct atsc_eit_section_info *section
> =
> +                                       &eit->section[k];
> +                               if(print_events(channel, section)) {
> +                                       fprintf(stderr, "%s(): error
> calling "
> +                                               "print_events()\n",
> __FUNCTION__);
> +                                       return -1;
> +                               }
> +                       }
> +               }
> +               fprintf(stdout, "%s\n", separator);
> +       }
> +
> +       return 0;
> +}
> +
> +static int open_demux(int *dmxfd)
> +{
> +       if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
> +               fprintf(stderr, "%s(): error calling
> dvbdemux_open_demux()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +       return 0;
> +}
> +
> +static int close_demux(int dmxfd)
> +{
> +       if(dvbdemux_stop(dmxfd)) {
> +               fprintf(stderr, "%s(): error calling
> dvbdemux_stop()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +       return 0;
> +}
> +
> +/* used other utilities as template and generalized here */
> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum
> atsc_section_tag tag,
> +       void **table_section)
> +{
> +       uint8_t filter[18];
> +       uint8_t mask[18];
> +       unsigned char sibuf[4096];
> +       int size;
> +       int ret;
> +       struct pollfd pollfd;
> +       struct section *section;
> +       struct section_ext *section_ext;
> +       struct atsc_section_psip *psip;
> +
> +       /* create a section filter for the table */
> +       memset(filter, 0, sizeof(filter));
> +       memset(mask, 0, sizeof(mask));
> +       filter[0] = tag;
> +       mask[0] = 0xFF;
> +       if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1,
> 1)) {
> +               fprintf(stderr, "%s(): error calling
> atsc_scan_table()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       /* poll for data */
> +       pollfd.fd = dmxfd;
> +       pollfd.events = POLLIN | POLLERR |POLLPRI;
> +       if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
> +               if(ctrl_c) {
> +                       return 0;
> +               }
> +               fprintf(stderr, "%s(): error calling poll()\n",
> __FUNCTION__);
> +               return -1;
> +       }
> +
> +       if(0 == ret) {
> +               return 0;
> +       }
> +
> +       /* read it */
> +       if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
> +               fprintf(stderr, "%s(): error calling read()\n",
> __FUNCTION__);
> +               return -1;
> +       }
> +
> +       /* parse section */
> +       section = section_codec(sibuf, size);
> +       if(NULL == section) {
> +               fprintf(stderr, "%s(): error calling
> section_codec()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       section_ext = section_ext_decode(section, 0);
> +       if(NULL == section_ext) {
> +               fprintf(stderr, "%s(): error calling
> section_ext_decode()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       psip = atsc_section_psip_decode(section_ext);
> +       if(NULL == psip) {
> +               fprintf(stderr,
> +                       "%s(): error calling
> atsc_section_psip_decode()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       *table_section = table_callback[tag & 0x0F](psip);
> +       if(NULL == *table_section) {
> +               fprintf(stderr, "%s(): error decode table section\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       return 1;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +       int i, dmxfd;
> +       struct dvbfe_handle *fe;
> +
> +       program = argv[0];
> +
> +       if(1 == argc) {
> +               usage();
> +               exit(-1);
> +       }
> +
> +       for( ; ; ) {
> +               char c;
> +
> +               if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
> +                       break;
> +               }
> +
> +               switch(c) {
> +               case 'a':
> +                       adapter = strtoll(optarg, NULL, 0);
> +                       break;
> +
> +               case 'f':
> +                       frequency = strtol(optarg, NULL, 0);
> +                       break;
> +
> +               case 'p':
> +                       period = strtol(optarg, NULL, 0);
> +                       /* each table covers 3 hours */
> +                       if((3 * MAX_NUM_EVENT_TABLES) < period) {
> +                               period = 3 * MAX_NUM_EVENT_TABLES;
> +                       }
> +                       break;
> +
> +               case 'm':
> +                       /* just stub, so far ATSC only has VSB_8 */
> +                       modulation = optarg;
> +                       break;
> +
> +               case 't':
> +                       enable_ett = 1;
> +                       break;
> +
> +               case 'h':
> +                       help();
> +                       exit(0);
> +
> +               default:
> +                       usage();
> +                       exit(-1);
> +               }
> +       }
> +
> +       memset(separator, '-', sizeof(separator));
> +       separator[79] = '\0';
> +       memset(&guide, 0, sizeof(struct atsc_virtual_channels_info));
> +       memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES *
> sizeof(uint16_t));
> +       memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES *
> sizeof(uint16_t));
> +
> +       if(open_frontend(&fe)) {
> +               fprintf(stderr, "%s(): error calling
> open_frontend()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       if(open_demux(&dmxfd)) {
> +               fprintf(stderr, "%s(): error calling open_demux()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       if(parse_stt(dmxfd)) {
> +               fprintf(stderr, "%s(): error calling parse_stt()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       if(parse_mgt(dmxfd)) {
> +               fprintf(stderr, "%s(): error calling parse_mgt()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       if(parse_tvct(dmxfd)) {
> +               fprintf(stderr, "%s(): error calling parse_tvct()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +#ifdef ENABLE_RRT
> +       if(parse_rrt(dmxfd)) {
> +               fprintf(stderr, "%s(): error calling parse_rrt()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +#endif
> +
> +       fprintf(stdout, "receiving EIT ");
> +       for(i = 0; i < guide.ch[0].num_eits; i++) {
> +               if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
> +                       fprintf(stderr, "%s(): error calling
> parse_eit()\n",
> +                               __FUNCTION__);
> +                       return -1;
> +               }
> +       }
> +       fprintf(stdout, "\n");
> +
> +       old_handler = signal(SIGINT, int_handler);
> +       if(enable_ett) {
> +               fprintf(stdout, "receiving ETT ");
> +               for(i = 0; i < guide.ch[0].num_eits; i++) {
> +                       if(0xFFFF != guide.ett_pid[i]) {
> +                               if(parse_ett(dmxfd, i,
> guide.ett_pid[i])) {
> +                                       fprintf(stderr, "%s(): error
> calling "
> +                                               "parse_eit()\n",
> __FUNCTION__);
> +                                       return -1;
> +                               }
> +                       }
> +                       if(ctrl_c) {
> +                               break;
> +                       }
> +               }
> +               fprintf(stdout, "\n");
> +       }
> +       signal(SIGINT, old_handler);
> +
> +       if(print_guide()) {
> +               fprintf(stderr, "%s(): error calling print_guide()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       if(cleanup_guide()) {
> +               fprintf(stderr, "%s(): error calling
> cleanup_guide()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       if(close_demux(dmxfd)) {
> +               fprintf(stderr, "%s(): error calling close_demux()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       if(close_frontend(fe)) {
> +               fprintf(stderr, "%s(): error calling close_demux()\n",
> +                       __FUNCTION__);
> +               return -1;
> +       }
> +
> +       return 0;
> +}
> diff -uprN dvb-apps/util/atsc_epg/Makefile
> dvb-apps_new/util/atsc_epg/Makefile
> --- dvb-apps/util/atsc_epg/Makefile     1969-12-31 18:00:00.000000000
> -0600
> +++ dvb-apps_new/util/atsc_epg/Makefile 2009-06-18 20:11:58.362985962
> -0500
> @@ -0,0 +1,16 @@
> +# Makefile for linuxtv.org dvb-apps/util/atsc_epg
> +
> +binaries = atsc_epg
> +
> +inst_bin = $(binaries)
> +
> +CPPFLAGS += -I../../lib -std=c99 -D_POSIX_SOURCE
> +#LDFLAGS  += -static -L../../lib/libdvbapi -L../../lib/libucsi
> +LDFLAGS  += -L../../lib/libdvbapi -L../../lib/libucsi
> +LDLIBS   += -ldvbapi -lucsi
> +
> +.PHONY: all
> +
> +all: $(binaries)
> +
> +include ../../Make.rules
> diff -uprN dvb-apps/util/atsc_epg/README dvb-apps_new/util/atsc_epg/README
> --- dvb-apps/util/atsc_epg/README       1969-12-31 18:00:00.000000000 -0600
> +++ dvb-apps_new/util/atsc_epg/README   2009-06-18 20:33:47.836924378 -0500
> @@ -0,0 +1,12 @@
> +Hi there,
> +
> +atsc_epg is a small utility for obtaining information such as programs, EPG
> +(electronic program guide) from an ATSC channel.
> +
> +Pulling the detailed information, i.e., option '-t', may take fairly long
> +time, or never ending, which is a bug of the PSIP generator. Ctrl+C can be
> +used to abort and the received parts will be printed.
> +
> +Enjoy,
> +Yufei
> +
> diff -uprN dvb-apps/util/Makefile dvb-apps_new/util/Makefile
> --- dvb-apps/util/Makefile      2009-06-18 19:43:30.034986539 -0500
> +++ dvb-apps_new/util/Makefile  2009-06-18 20:11:41.169986806 -0500
> @@ -3,6 +3,7 @@
>  .PHONY: all clean install
> 
>  all clean install:
> +       $(MAKE) -C atsc_epg $@
>         $(MAKE) -C av7110_loadkeys $@
>         $(MAKE) -C dib3000-watch $@
>         $(MAKE) -C dst-utils $@
> 

-- 
Even uttering "HI" or "HAO" is offensive, sometime, somewhere. Reader
discretion is advised.
--

My, the patch is still pretty well broken.

I leave it to Manu to help you further in the submission procedures ;)

As said, keep your Confucius stuff if you like.

I won't rant a second time on it.

But don't ever complain here, if others do have some good arguments too,
in their footers ...

Cheers,
Hermann









^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-20  0:41           ` hermann pitton
@ 2009-06-20  1:00             ` Yufei Yuan
  2009-06-20  1:28               ` hermann pitton
  0 siblings, 1 reply; 22+ messages in thread
From: Yufei Yuan @ 2009-06-20  1:00 UTC (permalink / raw)
  To: hermann pitton; +Cc: Manu Abraham, Linux Media Mailing List

Thanks for your time. It's my first time to do this, so I have been
trying to follow literally on the wiki page to do it right. If you can
elaborate a bit about what is broken? Is it the patch created
incorrectly, or it is pasted incorrectly, or the style is still
problematic?

I noticed that cutting and pasting from my console to the gmail
compose window does not seem working alright. How do you normally do
the inlining?

I have a full weekend to do this, and I do realize from the wiki page
that it does not appear to be simple, :)

I now simply disable the footer, don't worry.

Regards,

On Fri, Jun 19, 2009 at 7:41 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
>
> Am Donnerstag, den 18.06.2009, 20:39 -0500 schrieb Yufei Yuan:
>> This one is about the utility itself. I do apologize for the length
>> here as "inline" patch is preferred according to the guide and I don't
>> have any public online storage. Please let me know if this causes any
>> inconvenience.
>>
>> Signed-off-by: Yufei Yuan <yfyuan@gmail.com>
>>
>> diff -uprN dvb-apps/util/atsc_epg/atsc_epg.c
>> dvb-apps_new/util/atsc_epg/atsc_epg.c
>> --- dvb-apps/util/atsc_epg/atsc_epg.c   1969-12-31 18:00:00.000000000
>> -0600
>> +++ dvb-apps_new/util/atsc_epg/atsc_epg.c       2009-06-18
>> 20:17:24.527925142 -0500
>> @@ -0,0 +1,1249 @@
>> +/*
>> + * atsc_epg utility
>> + *
>> + * Copyright (C) 2009 Yufei Yuan <yfyuan@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.
>> + */
>> +
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <unistd.h>
>> +#include <string.h>
>> +#include <time.h>
>> +#include <signal.h>
>> +#include <sys/types.h>
>> +#include <sys/stat.h>
>> +#include <fcntl.h>
>> +#include <sys/ioctl.h>
>> +#include <sys/poll.h>
>> +#include <errno.h>
>> +#include <getopt.h>
>> +#include <stdarg.h>
>> +#include <libdvbapi/dvbfe.h>
>> +#include <libdvbapi/dvbdemux.h>
>> +#include <libucsi/dvb/section.h>
>> +#include <libucsi/atsc/section.h>
>> +#include <libucsi/atsc/types.h>
>> +
>> +#define TIMEOUT                                60
>> +#define RRT_TIMEOUT                    60
>> +#define MAX_NUM_EVENT_TABLES           128
>> +#define TITLE_BUFFER_LEN               4096
>> +#define MESSAGE_BUFFER_LEN             (16 * 1024)
>> +#define MAX_NUM_CHANNELS               16
>> +#define MAX_NUM_EVENTS_PER_CHANNEL     (4 * 24 * 7)
>> +
>> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum
>> atsc_section_tag tag,
>> +       void **table_section);
>> +
>> +static const char *program;
>> +static int adapter = 0;
>> +static int period = 12; /* hours */
>> +static int frequency;
>> +static int enable_ett = 0;
>> +static int ctrl_c = 0;
>> +static const char *modulation = NULL;
>> +static char separator[80];
>> +void (*old_handler)(int);
>> +
>> +struct atsc_string_buffer {
>> +       int buf_len;
>> +       int buf_pos;
>> +       char *string;
>> +};
>> +
>> +struct atsc_event_info {
>> +       uint16_t id;
>> +       struct tm start;
>> +       struct tm end;
>> +       int title_pos;
>> +       int title_len;
>> +       int msg_pos;
>> +       int msg_len;
>> +};
>> +
>> +struct atsc_eit_section_info {
>> +       uint8_t section_num;
>> +       uint8_t num_events;
>> +       uint8_t num_etms;
>> +       uint8_t num_received_etms;
>> +       struct atsc_event_info **events;
>> +};
>> +
>> +struct atsc_eit_info {
>> +       int num_eit_sections;
>> +       struct atsc_eit_section_info *section;
>> +};
>> +
>> +struct atsc_channel_info {
>> +       uint8_t num_eits;
>> +       uint8_t service_type;
>> +       char short_name[8];
>> +       uint16_t major_num;
>> +       uint16_t minor_num;
>> +       uint16_t tsid;
>> +       uint16_t prog_num;
>> +       uint16_t src_id;
>> +       struct atsc_eit_info *eit;
>> +       struct atsc_event_info *last_event;
>> +       int event_info_index;
>> +       struct atsc_event_info e[MAX_NUM_EVENTS_PER_CHANNEL];
>> +       struct atsc_string_buffer title_buf;
>> +       struct atsc_string_buffer msg_buf;
>> +};
>> +
>> +struct atsc_virtual_channels_info {
>> +       int num_channels;
>> +       uint16_t eit_pid[MAX_NUM_EVENT_TABLES];
>> +       uint16_t ett_pid[MAX_NUM_EVENT_TABLES];
>> +       struct atsc_channel_info ch[MAX_NUM_CHANNELS];
>> +} guide;
>> +
>> +struct mgt_table_name {
>> +       uint16_t range;
>> +       const char *string;
>> +};
>> +
>> +struct mgt_table_name mgt_tab_name_array[] = {
>> +       {0x0000, "terrestrial VCT with current_next_indictor=1"},
>> +       {0x0001, "terrestrial VCT with current_next_indictor=0"},
>> +       {0x0002, "cable VCT with current_next_indictor=1"},
>> +       {0x0003, "cable VCT with current_next_indictor=0"},
>> +       {0x0004, "channel ETT"},
>> +       {0x0005, "DCCSCT"},
>> +       {0x00FF, "reserved for future ATSC use"},
>> +       {0x017F, "EIT"},
>> +       {0x01FF, "reserved for future ATSC use"},
>> +       {0x027F, "event ETT"},
>> +       {0x02FF, "reserved for future ATSC use"}, /* FIXME */
>> +       {0x03FF, "RRT with rating region"},
>> +       {0x0FFF, "user private"},
>> +       {0x13FF, "reserved for future ATSC use"},
>> +       {0x14FF, "DCCT with dcc_id"},
>> +       {0xFFFF, "reserved for future ATSC use"}
>> +};
>> +
>> +const char *channel_modulation_mode[] = {
>> +       "",
>> +       "analog",
>> +       "SCTE mode 1",
>> +       "SCTE mode 2",
>> +       "ATSC 8VSB",
>> +       "ATSC 16VSB"
>> +};
>> +
>> +const char *channel_service_type[] = {
>> +       "",
>> +       "analog TV",
>> +       "ATSC digital TV",
>> +       "ATSC audio",
>> +       "ATSC data-only"
>> +};
>> +
>> +void *(*table_callback[16])(struct atsc_section_psip *) =
>> +{
>> +       NULL, NULL, NULL, NULL, NULL, NULL, NULL,
>> +       (void *(*)(struct atsc_section_psip *))atsc_mgt_section_codec,
>> +       (void *(*)(struct atsc_section_psip
>> *))atsc_tvct_section_codec,
>> +       (void *(*)(struct atsc_section_psip
>> *))atsc_cvct_section_codec,
>> +       (void *(*)(struct atsc_section_psip *))atsc_rrt_section_codec,
>> +       (void *(*)(struct atsc_section_psip *))atsc_eit_section_codec,
>> +       (void *(*)(struct atsc_section_psip *))atsc_ett_section_codec,
>> +       (void *(*)(struct atsc_section_psip *))atsc_stt_section_codec,
>> +       NULL, NULL
>> +};
>> +
>> +static void int_handler(int sig_num)
>> +{
>> +       if(SIGINT != sig_num) {
>> +               return;
>> +       }
>> +       ctrl_c = 1;
>> +}
>> +
>> +/* shamelessly stolen from dvbsnoop, but almost not modified */
>> +static uint32_t get_bits(const uint8_t *buf, int startbit, int
>> bitlen)
>> +{
>> +       const uint8_t *b;
>> +       uint32_t mask,tmp_long;
>> +       int bitHigh,i;
>> +
>> +       b = &buf[startbit / 8];
>> +       startbit %= 8;
>> +
>> +       bitHigh = 8;
>> +       tmp_long = b[0];
>> +       for (i = 0; i < ((bitlen-1) >> 3); i++) {
>> +               tmp_long <<= 8;
>> +               tmp_long  |= b[i+1];
>> +               bitHigh   += 8;
>> +       }
>> +
>> +       startbit = bitHigh - startbit - bitlen;
>> +       tmp_long = tmp_long >> startbit;
>> +       mask     = (1ULL << bitlen) - 1;
>> +       return tmp_long & mask;
>> +}
>> +
>> +static void usage(void)
>> +{
>> +       fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p
>> <period>]"
>> +               " [-m <modulation>] [-t] [-h]\n", program);
>> +}
>> +
>> +static void help(void)
>> +{
>> +       fprintf(stderr,
>> +       "\nhelp:\n"
>> +       "%s [-a <n>] -f <frequency> [-p <period>] [-m <modulation>]
>> [-t] [-h]\n"
>> +       "  -a: adapter index to use, (default 0)\n"
>> +       "  -f: tuning frequency\n"
>> +       "  -p: period in hours, (default 12)\n"
>> +       "  -m: modulation ATSC vsb_8|vsb_16 (default vsb_8)\n"
>> +       "  -t: enable ETT to receive program details, if available\n"
>> +       "  -h: display this message\n", program);
>> +}
>> +
>> +static int close_frontend(struct dvbfe_handle *fe)
>> +{
>> +       if(NULL == fe) {
>> +               fprintf(stderr, "%s(): NULL pointer detected\n",
>> __FUNCTION__);
>> +       }
>> +
>> +       dvbfe_close(fe);
>> +
>> +       return 0;
>> +}
>> +
>> +static int open_frontend(struct dvbfe_handle **fe)
>> +{
>> +       struct dvbfe_info fe_info;
>> +
>> +       if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
>> +               fprintf(stderr, "%s(): error calling dvbfe_open()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +       dvbfe_get_info(*fe, 0, &fe_info,
>> DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
>> +       if(DVBFE_TYPE_ATSC != fe_info.type) {
>> +               fprintf(stderr, "%s(): only ATSC frontend supported
>> currently\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +       fe_info.feparams.frequency = frequency;
>> +       fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
>> +       fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
>> +       fprintf(stdout, "tuning to %d Hz, please wait...\n",
>> frequency);
>> +       if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
>> +               fprintf(stderr, "%s(): cannot lock to %d Hz in %d
>> seconds\n",
>> +                       __FUNCTION__, frequency, TIMEOUT);
>> +               return -1;
>> +       }
>> +       fprintf(stdout, "tuner locked.\n");
>> +
>> +       return 0;
>> +}
>> +
>> +#if ENABLE_RRT
>> +/* this is untested as since this part of the library is broken */
>> +static int parse_rrt(int dmxfd)
>> +{
>> +       const enum atsc_section_tag tag = stag_atsc_rating_region;
>> +       struct atsc_rrt_section *rrt;
>> +       struct atsc_text *region_name;
>> +       struct atsc_text_string *atsc_str;
>> +       int i, j, ret;
>> +
>> +       i = 0;
>> +       fprintf(stdout, "waiting for RRT: ");
>> +       fflush(stdout);
>> +       while(i < RRT_TIMEOUT) {
>> +               ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
>> **)&rrt);
>> +               if(0 > ret) {
>> +                       fprintf(stderr, "%s(): error calling
>> atsc_scan_table()\n",
>> +                               __FUNCTION__);
>> +                       return -1;
>> +               }
>> +               if(0 == ret) {
>> +                       if(RRT_TIMEOUT > i) {
>> +                               fprintf(stdout, ".");
>> +                               fflush(stdout);
>> +                       } else {
>> +                               fprintf(stdout, "\nno RRT in %d
>> seconds\n",
>> +                                       RRT_TIMEOUT);
>> +                               return 0;
>> +                       }
>> +                       i += TIMEOUT;
>> +               } else {
>> +                       fprintf(stdout, "\n");
>> +                       fflush(stdout);
>> +                       break;
>> +               }
>> +       }
>> +
>> +       region_name = atsc_rrt_section_rating_region_name_text(rrt);
>> +       atsc_text_strings_for_each(region_name, atsc_str, i) {
>> +               struct atsc_text_string_segment *seg;
>> +
>> +               atsc_text_string_segments_for_each(atsc_str, seg, j) {
>> +                       const char *c;
>> +                       int k;
>> +                       if(seg->mode < 0x3E) {
>> +                               fprintf(stderr, "%s(): text mode of
>> 0x%02X "
>> +                                       "not supported yet\n",
>> +                                       __FUNCTION__, seg->mode);
>> +                               return -1;
>> +                       }
>> +                       c = (const char
>> *)atsc_text_string_segment_bytes(seg);
>> +                       for(k = 0; k < seg->number_bytes; k++) {
>> +                               fprintf(stdout, "%c", c[k]);
>> +                       }
>> +               }
>> +       }
>> +
>> +       return 0;
>> +}
>> +#endif
>> +
>> +static int parse_stt(int dmxfd)
>> +{
>> +       const enum atsc_section_tag tag = stag_atsc_system_time;
>> +       const struct atsc_stt_section *stt;
>> +       time_t rx_time;
>> +       time_t sys_time;
>> +       int ret;
>> +
>> +       ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
>> **)&stt);
>> +       if(0 > ret) {
>> +               fprintf(stderr, "%s(): error calling
>> atsc_scan_table()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +       if(0 == ret) {
>> +               fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
>> +               return 0;
>> +       }
>> +
>> +       rx_time = atsctime_to_unixtime(stt->system_time);
>> +       time(&sys_time);
>> +       fprintf(stdout, "system time: %s", ctime(&sys_time));
>> +       fprintf(stdout, "TS STT time: %s", ctime(&rx_time));
>> +
>> +       return 0;
>> +}
>> +
>> +static int parse_tvct(int dmxfd)
>> +{
>> +       int num_sections;
>> +       uint32_t section_pattern;
>> +       const enum atsc_section_tag tag =
>> stag_atsc_terrestrial_virtual_channel;
>> +       struct atsc_tvct_section *tvct;
>> +       struct atsc_tvct_channel *ch;
>> +       struct atsc_channel_info *curr_info;
>> +       int i, k, ret;
>> +
>> +       section_pattern = 0;
>> +       num_sections = -1;
>> +
>> +       do {
>> +               ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
>> **)&tvct);
>> +               if(0 > ret) {
>> +                       fprintf(stderr, "%s(): error calling
>> atsc_scan_table()\n",
>> +                       __FUNCTION__);
>> +                       return -1;
>> +               }
>> +               if(0 == ret) {
>> +                       fprintf(stdout, "no TVCT in %d seconds\n",
>> TIMEOUT);
>> +                       return 0;
>> +               }
>> +
>> +               if(-1 == num_sections) {
>> +                       num_sections = 1 +
>> tvct->head.ext_head.last_section_number;
>> +                       if(32 < num_sections) {
>> +                               fprintf(stderr, "%s(): no support yet
>> for "
>> +                                       "tables having more than 32
>> sections\n",
>> +                                       __FUNCTION__);
>> +                               return -1;
>> +                       }
>> +               } else {
>> +                       if(num_sections !=
>> +                               1 +
>> tvct->head.ext_head.last_section_number) {
>> +                               fprintf(stderr,
>> +                                       "%s(): last section number
>> does not match\n",
>> +                                       __FUNCTION__);
>> +                               return -1;
>> +                       }
>> +               }
>> +               if(section_pattern & (1 <<
>> tvct->head.ext_head.section_number)) {
>> +                       continue;
>> +               }
>> +               section_pattern |= 1 <<
>> tvct->head.ext_head.section_number;
>> +
>> +               if(MAX_NUM_CHANNELS < guide.num_channels +
>> +                       tvct->num_channels_in_section) {
>> +                       fprintf(stderr, "%s(): no support for more
>> than %d "
>> +                               "virtual channels in a pyhsical
>> channel\n",
>> +                               __FUNCTION__, MAX_NUM_CHANNELS);
>> +                       return -1;
>> +               }
>> +               curr_info = &guide.ch[guide.num_channels];
>> +               guide.num_channels += tvct->num_channels_in_section;
>> +
>> +       atsc_tvct_section_channels_for_each(tvct, ch, i) {
>> +               /* initialize the curr_info structure */
>> +               /* each EIT covers 3 hours */
>> +               curr_info->num_eits = (period / 3) + !!(period % 3);
>> +               while (curr_info->num_eits &&
>> +                       (0xFFFF == guide.eit_pid[curr_info->num_eits -
>> 1])) {
>> +                       curr_info->num_eits -= 1;
>> +               }
>> +               if(curr_info->eit) {
>> +                       fprintf(stderr, "%s(): non-NULL pointer
>> detected "
>> +                               "during initialization",
>> __FUNCTION__);
>> +                       return -1;
>> +               }
>> +               if(NULL == (curr_info->eit =
>> calloc(curr_info->num_eits,
>> +                       sizeof(struct atsc_eit_info)))) {
>> +                       fprintf(stderr, "%s(): error calling
>> calloc()\n",
>> +                               __FUNCTION__);
>> +                       return -1;
>> +               }
>> +               if(NULL == (curr_info->title_buf.string =
>> calloc(TITLE_BUFFER_LEN,
>> +                       sizeof(char)))) {
>> +                       fprintf(stderr, "%s(): error calling
>> calloc()\n",
>> +                               __FUNCTION__);
>> +                       return -1;
>> +               }
>> +               curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
>> +               curr_info->title_buf.buf_pos = 0;
>> +
>> +               if(NULL == (curr_info->msg_buf.string =
>> calloc(MESSAGE_BUFFER_LEN,
>> +                       sizeof(char)))) {
>> +                       fprintf(stderr, "%s(): error calling
>> calloc()\n",
>> +                               __FUNCTION__);
>> +                       return -1;
>> +               }
>> +               curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
>> +               curr_info->msg_buf.buf_pos = 0;
>> +
>> +               for(k = 0; k < 7; k++) {
>> +                       curr_info->short_name[k] =
>> +                               get_bits((const uint8_t
>> *)ch->short_name,
>> +                               k * 16, 16);
>> +               }
>> +               curr_info->service_type = ch->service_type;
>> +               curr_info->major_num = ch->major_channel_number;
>> +               curr_info->minor_num = ch->minor_channel_number;
>> +               curr_info->tsid = ch->channel_TSID;
>> +               curr_info->prog_num = ch->program_number;
>> +               curr_info->src_id = ch->source_id;
>> +               curr_info++;
>> +               }
>> +       } while(section_pattern != (uint32_t)((1 << num_sections) -
>> 1));
>> +
>> +       return 0;
>> +}
>> +
>> +static int match_event(struct atsc_eit_info *eit, uint16_t event_id,
>> +       struct atsc_event_info **event, uint8_t *curr_index)
>> +{
>> +       int j, k;
>> +       struct atsc_eit_section_info *section;
>> +
>> +       if(NULL == eit || NULL == event || NULL == curr_index) {
>> +               fprintf(stderr, "%s(): NULL pointer detected\n",
>> __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       for(j = 0; j < eit->num_eit_sections; j++) {
>> +               section = &eit->section[j];
>> +
>> +               for(k = 0; k < section->num_events; k++) {
>> +                       if(section->events[k] &&
>> section->events[k]->id ==
>> +                               event_id) {
>> +                               *event = section->events[k];
>> +                               break;
>> +                       }
>> +               }
>> +               if(*event) {
>> +                       *curr_index = j;
>> +                       break;
>> +               }
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int parse_message(struct atsc_channel_info *channel,
>> +       struct atsc_ett_section *ett, struct atsc_event_info *event)
>> +{
>> +       int i, j;
>> +       struct atsc_text *text;
>> +       struct atsc_text_string *str;
>> +
>> +       if(NULL == ett || NULL == event || NULL == channel) {
>> +               fprintf(stderr, "%s(): NULL pointer detected\n",
>> __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       text = atsc_ett_section_extended_text_message(ett);
>> +       atsc_text_strings_for_each(text, str, i) {
>> +               struct atsc_text_string_segment *seg;
>> +
>> +               atsc_text_string_segments_for_each(str, seg, j) {
>> +                       event->msg_pos = channel->msg_buf.buf_pos;
>> +                       if(0 > atsc_text_segment_decode(seg,
>> +                               (uint8_t **)&channel->msg_buf.string,
>> +                               (size_t *)&channel->msg_buf.buf_len,
>> +                               (size_t *)&channel->msg_buf.buf_pos))
>> {
>> +                               fprintf(stderr, "%s(): error calling "
>> +
>> "atsc_text_segment_decode()\n",
>> +                                       __FUNCTION__);
>> +                               return -1;
>> +                       }
>> +                       event->msg_len = 1 + channel->msg_buf.buf_pos
>> -
>> +                               event->msg_pos;
>> +               }
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int parse_ett(int dmxfd, int index, uint16_t pid)
>> +{
>> +       uint8_t curr_index;
>> +       uint32_t section_pattern;
>> +       const enum atsc_section_tag tag = stag_atsc_extended_text;
>> +       struct atsc_eit_info *eit;
>> +       struct atsc_ett_section *ett;
>> +       struct atsc_channel_info *channel;
>> +       struct atsc_event_info *event;
>> +       struct atsc_eit_section_info *section;
>> +       uint16_t source_id, event_id;
>> +       int c, ret;
>> +
>> +       if(0xFFFF == guide.ett_pid[index]) {
>> +               return 0;
>> +       }
>> +
>> +       for(c = 0; c < guide.num_channels; c++) {
>> +               channel = &guide.ch[c];
>> +               eit = &channel->eit[index];
>> +
>> +               section_pattern = 0;
>> +               while(section_pattern !=
>> +                       (uint32_t)((1 << eit->num_eit_sections) - 1))
>> {
>> +                       if(ctrl_c) {
>> +                               return 0;
>> +                       }
>> +                       ret = atsc_scan_table(dmxfd, pid, tag, (void
>> **)&ett);
>> +                       fprintf(stdout, ".");
>> +                       fflush(stdout);
>> +                       if(0 > ret) {
>> +                               fprintf(stderr, "%s(): error calling "
>> +                                       "atsc_scan_table()\n",
>> __FUNCTION__);
>> +                               return -1;
>> +                       }
>> +                       if(0 == ret) {
>> +                               fprintf(stdout, "no ETT %d in %d
>> seconds\n",
>> +                                       index, TIMEOUT);
>> +                               return 0;
>> +                       }
>> +
>> +                       source_id = ett->ETM_source_id;
>> +                       event_id = ett->ETM_sub_id;
>> +                       if(source_id != channel->src_id) {
>> +                               continue;
>> +                       }
>> +
>> +                       event = NULL;
>> +                       if(match_event(eit, event_id, &event,
>> &curr_index)) {
>> +                               fprintf(stderr, "%s(): error calling "
>> +                                       "match_event()\n",
>> __FUNCTION__);
>> +                               return -1;
>> +                       }
>> +                       if(NULL == event) {
>> +                               continue;
>> +                       }
>> +                       if(section_pattern & (1 << curr_index)) {
>> +                               /* the section has been filled, so
>> skip,
>> +                                * not consider version yet
>> +                                */
>> +                               continue;
>> +                       }
>> +                       if(event->msg_len) {
>> +                               /* the message has been filled */
>> +                               continue;
>> +                       }
>> +
>> +                       if(parse_message(channel, ett, event)) {
>> +                               fprintf(stderr, "%s(): error calling "
>> +                                       "parse_message()\n",
>> __FUNCTION__);
>> +                               return -1;
>> +                       }
>> +                       section = &eit->section[curr_index];
>> +                       if(++section->num_received_etms ==
>> section->num_etms) {
>> +                               section_pattern |= 1 << curr_index;
>> +                       }
>> +               }
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int parse_events(struct atsc_channel_info *curr_info,
>> +       struct atsc_eit_section *eit, struct atsc_eit_section_info
>> *section)
>> +{
>> +       int i, j, k;
>> +       struct atsc_eit_event *e;
>> +       time_t start_time, end_time;
>> +
>> +       if(NULL == curr_info || NULL == eit) {
>> +               fprintf(stderr, "%s(): NULL pointer detected\n",
>> __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       atsc_eit_section_events_for_each(eit, e, i) {
>> +               struct atsc_text *title;
>> +               struct atsc_text_string *str;
>> +               struct atsc_event_info *e_info =
>> +                       &curr_info->e[curr_info->event_info_index];
>> +
>> +               if(0 == i && curr_info->last_event) {
>> +                       if(e->event_id == curr_info->last_event->id) {
>> +                               section->events[i] = NULL;
>> +                               /* skip if it's the same event
>> spanning
>> +                                * over sections
>> +                                */
>> +                               continue;
>> +                       }
>> +               }
>> +               curr_info->event_info_index += 1;
>> +               section->events[i] = e_info;
>> +               e_info->id = e->event_id;
>> +               start_time = atsctime_to_unixtime(e->start_time);
>> +               end_time = start_time + e->length_in_seconds;
>> +               localtime_r(&start_time, &e_info->start);
>> +               localtime_r(&end_time, &e_info->end);
>> +               if(0 != e->ETM_location && 3 != e->ETM_location) {
>> +                       /* FIXME assume 1 and 2 is interchangable as
>> of now */
>> +                       section->num_etms++;
>> +               }
>> +
>> +               title = atsc_eit_event_name_title_text(e);
>> +               atsc_text_strings_for_each(title, str, j) {
>> +                       struct atsc_text_string_segment *seg;
>> +
>> +                       atsc_text_string_segments_for_each(str, seg,
>> k) {
>> +                               e_info->title_pos =
>> curr_info->title_buf.buf_pos;
>> +                               if(0 > atsc_text_segment_decode(seg,
>> +                                       (uint8_t
>> **)&curr_info->title_buf.string,
>> +                                       (size_t
>> *)&curr_info->title_buf.buf_len,
>> +                                       (size_t
>> *)&curr_info->title_buf.buf_pos)) {
>> +                                       fprintf(stderr, "%s(): error
>> calling "
>> +
>> "atsc_text_segment_decode()\n",
>> +                                               __FUNCTION__);
>> +                                       return -1;
>> +                               }
>> +                               e_info->title_len =
>> curr_info->title_buf.buf_pos -
>> +                                       e_info->title_pos + 1;
>> +                       }
>> +               }
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int parse_eit(int dmxfd, int index, uint16_t pid)
>> +{
>> +       int num_sections;
>> +       uint8_t section_num;
>> +       uint8_t curr_channel_index;
>> +       uint32_t section_pattern;
>> +       const enum atsc_section_tag tag = stag_atsc_event_information;
>> +       struct atsc_eit_section *eit;
>> +       struct atsc_channel_info *curr_info;
>> +       struct atsc_eit_info *eit_info;
>> +       struct atsc_eit_section_info *section;
>> +       uint16_t source_id;
>> +       uint32_t eit_instance_pattern = 0;
>> +       int i, k, ret;
>> +
>> +       while(eit_instance_pattern !=
>> +               (uint32_t)((1 << guide.num_channels) - 1)) {
>> +               source_id = 0xFFFF;
>> +               section_pattern = 0;
>> +               num_sections = -1;
>> +
>> +               do {
>> +                       ret = atsc_scan_table(dmxfd, pid, tag, (void
>> **)&eit);
>> +                       fprintf(stdout, ".");
>> +                       fflush(stdout);
>> +                       if(0 > ret) {
>> +                               fprintf(stderr, "%s(): error calling "
>> +                                       "atsc_scan_table()\n",
>> __FUNCTION__);
>> +                               return -1;
>> +                       }
>> +                       if(0 == ret) {
>> +                               fprintf(stdout, "no EIT %d in %d
>> seconds\n",
>> +                                       index, TIMEOUT);
>> +                               return 0;
>> +                       }
>> +
>> +                       if(0xFFFF == source_id) {
>> +                       source_id = atsc_eit_section_source_id(eit);
>> +                       for(k = 0; k < guide.num_channels; k++) {
>> +                               if(source_id == guide.ch[k].src_id) {
>> +                                       curr_info = &guide.ch[k];
>> +                                       curr_channel_index = k;
>> +                                       if(0 == index) {
>> +                                               curr_info->last_event
>> = NULL;
>> +                                       }
>> +                                       break;
>> +                               }
>> +                       }
>> +                       if(k == guide.num_channels) {
>> +                               fprintf(stderr, "%s(): cannot find
>> source_id "
>> +                                       "0x%04X in the EIT\n",
>> +                                       __FUNCTION__, source_id);
>> +                               return -1;
>> +                       }
>> +                       } else {
>> +                               if(source_id !=
>> +
>> atsc_eit_section_source_id(eit)) {
>> +                                       continue;
>> +                               }
>> +                       }
>> +                       if(eit_instance_pattern & (1 <<
>> curr_channel_index)) {
>> +                               /* we have received this instance,
>> +                                * so quit quick
>> +                                */
>> +                               break;
>> +                       }
>> +
>> +                       if(-1 == num_sections) {
>> +                               num_sections = 1 +
>> +
>> eit->head.ext_head.last_section_number;
>> +                               if(32 < num_sections) {
>> +                                       fprintf(stderr,
>> +                                               "%s(): no support yet
>> for "
>> +                                               "tables having more
>> than "
>> +                                               "32 sections\n",
>> __FUNCTION__);
>> +                                       return -1;
>> +                               }
>> +                       } else {
>> +                               if(num_sections != 1 +
>> +
>> eit->head.ext_head.last_section_number) {
>> +                                       fprintf(stderr,
>> +                                               "%s(): last section
>> number "
>> +                                               "does not match\n",
>> +                                               __FUNCTION__);
>> +                                       return -1;
>> +                               }
>> +                       }
>> +                       if(section_pattern &
>> +                               (1 <<
>> eit->head.ext_head.section_number)) {
>> +                               continue;
>> +                       }
>> +                       section_pattern |= 1 <<
>> eit->head.ext_head.section_number;
>> +
>> +                       eit_info = &curr_info->eit[index];
>> +                       if(NULL == (eit_info->section =
>> +                               realloc(eit_info->section,
>> +                               (eit_info->num_eit_sections + 1) *
>> +                               sizeof(struct
>> atsc_eit_section_info)))) {
>> +                               fprintf(stderr,
>> +                                       "%s(): error calling
>> realloc()\n",
>> +                                       __FUNCTION__);
>> +                               return -1;
>> +                       }
>> +                       section_num =
>> eit->head.ext_head.section_number;
>> +                       if(0 == eit_info->num_eit_sections) {
>> +                               eit_info->num_eit_sections = 1;
>> +                               section = eit_info->section;
>> +                       } else {
>> +                               /* have to sort it into section order
>> +                                * (temporal order)
>> +                                */
>> +                               for(i = 0; i <
>> eit_info->num_eit_sections; i++) {
>> +
>> if(eit_info->section[i].section_num >
>> +                                               section_num) {
>> +                                               break;
>> +                                       }
>> +                               }
>> +                               memmove(&eit_info->section[i + 1],
>> +                                       &eit_info->section[i],
>> +                                       (eit_info->num_eit_sections -
>> i) *
>> +                                       sizeof(struct
>> atsc_eit_section_info));
>> +                               section = &eit_info->section[i - 1];
>> +                               section = &eit_info->section[i];
>> +                               eit_info->num_eit_sections += 1;
>> +                       }
>> +
>> +                       section->section_num = section_num;
>> +                       section->num_events =
>> eit->num_events_in_section;
>> +                       section->num_etms = 0;
>> +                       section->num_received_etms = 0;
>> +                       if(NULL == (section->events =
>> calloc(section->num_events,
>> +                               sizeof(struct atsc_event_info *)))) {
>> +                               fprintf(stderr, "%s(): error calling
>> calloc()\n",
>> +                                       __FUNCTION__);
>> +                               return -1;
>> +                       }
>> +                       if(parse_events(curr_info, eit, section)) {
>> +                               fprintf(stderr, "%s(): error calling "
>> +                                       "parse_events()\n",
>> __FUNCTION__);
>> +                               return -1;
>> +                       }
>> +               } while(section_pattern != (uint32_t)((1 <<
>> num_sections) - 1));
>> +               eit_instance_pattern |= 1 << curr_channel_index;
>> +       }
>> +
>> +       for(i = 0; i < guide.num_channels; i++) {
>> +               struct atsc_channel_info *channel = &guide.ch[i];
>> +               struct atsc_eit_info *ei = &channel->eit[index];
>> +               struct atsc_eit_section_info *s;
>> +
>> +               if(0 == ei->num_eit_sections) {
>> +                       channel->last_event = NULL;
>> +                       continue;
>> +               }
>> +               s = &ei->section[ei->num_eit_sections - 1];
>> +               /* BUG: it's incorrect when last section has no event
>> */
>> +               if(0 == s->num_events) {
>> +                       channel->last_event = NULL;
>> +                       continue;
>> +               }
>> +               channel->last_event = s->events[s->num_events - 1];
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int parse_mgt(int dmxfd)
>> +{
>> +       const enum atsc_section_tag tag = stag_atsc_master_guide;
>> +       struct atsc_mgt_section *mgt;
>> +       struct atsc_mgt_table *t;
>> +       int i, j, ret;
>> +
>> +       ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
>> **)&mgt);
>> +       if(0 > ret) {
>> +               fprintf(stderr, "%s(): error calling
>> atsc_scan_table()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +       if(0 == ret) {
>> +               fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
>> +               return 0;
>> +       }
>> +
>> +       fprintf(stdout, "MGT table:\n");
>> +       atsc_mgt_section_tables_for_each(mgt, t, i) {
>> +               struct mgt_table_name table;
>> +
>> +       for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
>> +               sizeof(struct mgt_table_name)); j++) {
>> +               if(t->table_type > mgt_tab_name_array[j].range) {
>> +                       continue;
>> +               }
>> +               table = mgt_tab_name_array[j];
>> +               if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
>> +                       mgt_tab_name_array[j].range) {
>> +                       j = -1;
>> +               } else {
>> +                       j = t->table_type - mgt_tab_name_array[j -
>> 1].range - 1;
>> +                       if(0x017F == table.range) {
>> +                               guide.eit_pid[j] = t->table_type_PID;
>> +                       } else if (0x027F == table.range) {
>> +                               guide.ett_pid[j] = t->table_type_PID;
>> +                       }
>> +               }
>> +               break;
>> +       }
>> +
>> +               fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X,
>> %s", i,
>> +                   t->table_type, t->table_type_PID, table.string);
>> +               if(-1 != j) {
>> +                   fprintf(stdout, " %d", j);
>> +               }
>> +               fprintf(stdout, "\n");
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int cleanup_guide(void)
>> +{
>> +       int i, j, k;
>> +
>> +       for(i = 0; i < guide.num_channels; i++) {
>> +               struct atsc_channel_info *channel = &guide.ch[i];
>> +
>> +               if(channel->title_buf.string) {
>> +                       free(channel->title_buf.string);
>> +               }
>> +               if(channel->msg_buf.string) {
>> +                       free(channel->msg_buf.string);
>> +               }
>> +               for(j = 0; j < channel->num_eits; j++) {
>> +                       struct atsc_eit_info *eit = &channel->eit[j];
>> +
>> +                       for(k = 0; k < eit->num_eit_sections; k++) {
>> +                               struct atsc_eit_section_info *section
>> =
>> +                                       &eit->section[k];
>> +                               if(section->num_events) {
>> +                                       free(section->events);
>> +                               }
>> +                       }
>> +                       if(k) {
>> +                               free(eit->section);
>> +                       }
>> +               }
>> +               if(j) {
>> +                       free(channel->eit);
>> +               }
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int print_events(struct atsc_channel_info *channel,
>> +       struct atsc_eit_section_info *section)
>> +{
>> +       int m;
>> +       char line[256];
>> +
>> +       if(NULL == section) {
>> +               fprintf(stderr, "%s(): NULL pointer detected",
>> __FUNCTION__);
>> +               return -1;
>> +       }
>> +       for(m = 0; m < section->num_events; m++) {
>> +               struct atsc_event_info *event =
>> +                       section->events[m];
>> +
>> +               if(NULL == event) {
>> +                       continue;
>> +               }
>> +               fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
>> +                       event->start.tm_hour, event->start.tm_min,
>> +                       event->end.tm_hour, event->end.tm_min);
>> +               snprintf(line, event->title_len, "%s",
>> +                       &channel->title_buf.string[event->title_pos]);
>> +               line[event->title_len] = '\0';
>> +               fprintf(stdout, "%s\n", line);
>> +               if(event->msg_len) {
>> +                       int len = event->msg_len;
>> +                       int pos = event->msg_pos;
>> +                       size_t part;
>> +
>> +                       do {
>> +                               part = len > 255 ? 255 : len;
>> +                               snprintf(line, part, "%s",
>> +
>> &channel->msg_buf.string[pos]);
>> +                               line[part] = '\0';
>> +                               fprintf(stdout, "%s", line);
>> +                               len -= part;
>> +                               pos += part;
>> +                       } while(0 < len);
>> +                       fprintf(stdout, "\n");
>> +               }
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int print_guide(void)
>> +{
>> +       int i, j, k;
>> +
>> +       fprintf(stdout, "%s\n", separator);
>> +       for(i = 0; i < guide.num_channels; i++) {
>> +               struct atsc_channel_info *channel = &guide.ch[i];
>> +
>> +               fprintf(stdout, "%d.%d  %s\n", channel->major_num,
>> +                       channel->minor_num, channel->short_name);
>> +               for(j = 0; j < channel->num_eits; j++) {
>> +                       struct atsc_eit_info *eit = &channel->eit[j];
>> +
>> +                       for(k = 0; k < eit->num_eit_sections; k++) {
>> +                               struct atsc_eit_section_info *section
>> =
>> +                                       &eit->section[k];
>> +                               if(print_events(channel, section)) {
>> +                                       fprintf(stderr, "%s(): error
>> calling "
>> +                                               "print_events()\n",
>> __FUNCTION__);
>> +                                       return -1;
>> +                               }
>> +                       }
>> +               }
>> +               fprintf(stdout, "%s\n", separator);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int open_demux(int *dmxfd)
>> +{
>> +       if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
>> +               fprintf(stderr, "%s(): error calling
>> dvbdemux_open_demux()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int close_demux(int dmxfd)
>> +{
>> +       if(dvbdemux_stop(dmxfd)) {
>> +               fprintf(stderr, "%s(): error calling
>> dvbdemux_stop()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +       return 0;
>> +}
>> +
>> +/* used other utilities as template and generalized here */
>> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum
>> atsc_section_tag tag,
>> +       void **table_section)
>> +{
>> +       uint8_t filter[18];
>> +       uint8_t mask[18];
>> +       unsigned char sibuf[4096];
>> +       int size;
>> +       int ret;
>> +       struct pollfd pollfd;
>> +       struct section *section;
>> +       struct section_ext *section_ext;
>> +       struct atsc_section_psip *psip;
>> +
>> +       /* create a section filter for the table */
>> +       memset(filter, 0, sizeof(filter));
>> +       memset(mask, 0, sizeof(mask));
>> +       filter[0] = tag;
>> +       mask[0] = 0xFF;
>> +       if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1,
>> 1)) {
>> +               fprintf(stderr, "%s(): error calling
>> atsc_scan_table()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       /* poll for data */
>> +       pollfd.fd = dmxfd;
>> +       pollfd.events = POLLIN | POLLERR |POLLPRI;
>> +       if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
>> +               if(ctrl_c) {
>> +                       return 0;
>> +               }
>> +               fprintf(stderr, "%s(): error calling poll()\n",
>> __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       if(0 == ret) {
>> +               return 0;
>> +       }
>> +
>> +       /* read it */
>> +       if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
>> +               fprintf(stderr, "%s(): error calling read()\n",
>> __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       /* parse section */
>> +       section = section_codec(sibuf, size);
>> +       if(NULL == section) {
>> +               fprintf(stderr, "%s(): error calling
>> section_codec()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       section_ext = section_ext_decode(section, 0);
>> +       if(NULL == section_ext) {
>> +               fprintf(stderr, "%s(): error calling
>> section_ext_decode()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       psip = atsc_section_psip_decode(section_ext);
>> +       if(NULL == psip) {
>> +               fprintf(stderr,
>> +                       "%s(): error calling
>> atsc_section_psip_decode()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       *table_section = table_callback[tag & 0x0F](psip);
>> +       if(NULL == *table_section) {
>> +               fprintf(stderr, "%s(): error decode table section\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       return 1;
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +       int i, dmxfd;
>> +       struct dvbfe_handle *fe;
>> +
>> +       program = argv[0];
>> +
>> +       if(1 == argc) {
>> +               usage();
>> +               exit(-1);
>> +       }
>> +
>> +       for( ; ; ) {
>> +               char c;
>> +
>> +               if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
>> +                       break;
>> +               }
>> +
>> +               switch(c) {
>> +               case 'a':
>> +                       adapter = strtoll(optarg, NULL, 0);
>> +                       break;
>> +
>> +               case 'f':
>> +                       frequency = strtol(optarg, NULL, 0);
>> +                       break;
>> +
>> +               case 'p':
>> +                       period = strtol(optarg, NULL, 0);
>> +                       /* each table covers 3 hours */
>> +                       if((3 * MAX_NUM_EVENT_TABLES) < period) {
>> +                               period = 3 * MAX_NUM_EVENT_TABLES;
>> +                       }
>> +                       break;
>> +
>> +               case 'm':
>> +                       /* just stub, so far ATSC only has VSB_8 */
>> +                       modulation = optarg;
>> +                       break;
>> +
>> +               case 't':
>> +                       enable_ett = 1;
>> +                       break;
>> +
>> +               case 'h':
>> +                       help();
>> +                       exit(0);
>> +
>> +               default:
>> +                       usage();
>> +                       exit(-1);
>> +               }
>> +       }
>> +
>> +       memset(separator, '-', sizeof(separator));
>> +       separator[79] = '\0';
>> +       memset(&guide, 0, sizeof(struct atsc_virtual_channels_info));
>> +       memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES *
>> sizeof(uint16_t));
>> +       memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES *
>> sizeof(uint16_t));
>> +
>> +       if(open_frontend(&fe)) {
>> +               fprintf(stderr, "%s(): error calling
>> open_frontend()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       if(open_demux(&dmxfd)) {
>> +               fprintf(stderr, "%s(): error calling open_demux()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       if(parse_stt(dmxfd)) {
>> +               fprintf(stderr, "%s(): error calling parse_stt()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       if(parse_mgt(dmxfd)) {
>> +               fprintf(stderr, "%s(): error calling parse_mgt()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       if(parse_tvct(dmxfd)) {
>> +               fprintf(stderr, "%s(): error calling parse_tvct()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +#ifdef ENABLE_RRT
>> +       if(parse_rrt(dmxfd)) {
>> +               fprintf(stderr, "%s(): error calling parse_rrt()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +#endif
>> +
>> +       fprintf(stdout, "receiving EIT ");
>> +       for(i = 0; i < guide.ch[0].num_eits; i++) {
>> +               if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
>> +                       fprintf(stderr, "%s(): error calling
>> parse_eit()\n",
>> +                               __FUNCTION__);
>> +                       return -1;
>> +               }
>> +       }
>> +       fprintf(stdout, "\n");
>> +
>> +       old_handler = signal(SIGINT, int_handler);
>> +       if(enable_ett) {
>> +               fprintf(stdout, "receiving ETT ");
>> +               for(i = 0; i < guide.ch[0].num_eits; i++) {
>> +                       if(0xFFFF != guide.ett_pid[i]) {
>> +                               if(parse_ett(dmxfd, i,
>> guide.ett_pid[i])) {
>> +                                       fprintf(stderr, "%s(): error
>> calling "
>> +                                               "parse_eit()\n",
>> __FUNCTION__);
>> +                                       return -1;
>> +                               }
>> +                       }
>> +                       if(ctrl_c) {
>> +                               break;
>> +                       }
>> +               }
>> +               fprintf(stdout, "\n");
>> +       }
>> +       signal(SIGINT, old_handler);
>> +
>> +       if(print_guide()) {
>> +               fprintf(stderr, "%s(): error calling print_guide()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       if(cleanup_guide()) {
>> +               fprintf(stderr, "%s(): error calling
>> cleanup_guide()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       if(close_demux(dmxfd)) {
>> +               fprintf(stderr, "%s(): error calling close_demux()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       if(close_frontend(fe)) {
>> +               fprintf(stderr, "%s(): error calling close_demux()\n",
>> +                       __FUNCTION__);
>> +               return -1;
>> +       }
>> +
>> +       return 0;
>> +}
>> diff -uprN dvb-apps/util/atsc_epg/Makefile
>> dvb-apps_new/util/atsc_epg/Makefile
>> --- dvb-apps/util/atsc_epg/Makefile     1969-12-31 18:00:00.000000000
>> -0600
>> +++ dvb-apps_new/util/atsc_epg/Makefile 2009-06-18 20:11:58.362985962
>> -0500
>> @@ -0,0 +1,16 @@
>> +# Makefile for linuxtv.org dvb-apps/util/atsc_epg
>> +
>> +binaries = atsc_epg
>> +
>> +inst_bin = $(binaries)
>> +
>> +CPPFLAGS += -I../../lib -std=c99 -D_POSIX_SOURCE
>> +#LDFLAGS  += -static -L../../lib/libdvbapi -L../../lib/libucsi
>> +LDFLAGS  += -L../../lib/libdvbapi -L../../lib/libucsi
>> +LDLIBS   += -ldvbapi -lucsi
>> +
>> +.PHONY: all
>> +
>> +all: $(binaries)
>> +
>> +include ../../Make.rules
>> diff -uprN dvb-apps/util/atsc_epg/README dvb-apps_new/util/atsc_epg/README
>> --- dvb-apps/util/atsc_epg/README       1969-12-31 18:00:00.000000000 -0600
>> +++ dvb-apps_new/util/atsc_epg/README   2009-06-18 20:33:47.836924378 -0500
>> @@ -0,0 +1,12 @@
>> +Hi there,
>> +
>> +atsc_epg is a small utility for obtaining information such as programs, EPG
>> +(electronic program guide) from an ATSC channel.
>> +
>> +Pulling the detailed information, i.e., option '-t', may take fairly long
>> +time, or never ending, which is a bug of the PSIP generator. Ctrl+C can be
>> +used to abort and the received parts will be printed.
>> +
>> +Enjoy,
>> +Yufei
>> +
>> diff -uprN dvb-apps/util/Makefile dvb-apps_new/util/Makefile
>> --- dvb-apps/util/Makefile      2009-06-18 19:43:30.034986539 -0500
>> +++ dvb-apps_new/util/Makefile  2009-06-18 20:11:41.169986806 -0500
>> @@ -3,6 +3,7 @@
>>  .PHONY: all clean install
>>
>>  all clean install:
>> +       $(MAKE) -C atsc_epg $@
>>         $(MAKE) -C av7110_loadkeys $@
>>         $(MAKE) -C dib3000-watch $@
>>         $(MAKE) -C dst-utils $@
>>
>
> --
> Even uttering "HI" or "HAO" is offensive, sometime, somewhere. Reader
> discretion is advised.
> --
>
> My, the patch is still pretty well broken.
>
> I leave it to Manu to help you further in the submission procedures ;)
>
> As said, keep your Confucius stuff if you like.
>
> I won't rant a second time on it.
>
> But don't ever complain here, if others do have some good arguments too,
> in their footers ...
>
> Cheers,
> Hermann
>
>
>
>
>
>
>
>
>

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-20  1:00             ` Yufei Yuan
@ 2009-06-20  1:28               ` hermann pitton
  2009-06-20  2:38                 ` Yufei Yuan
  0 siblings, 1 reply; 22+ messages in thread
From: hermann pitton @ 2009-06-20  1:28 UTC (permalink / raw)
  To: Yufei Yuan; +Cc: Manu Abraham, Linux Media Mailing List

Hi,

Am Freitag, den 19.06.2009, 20:00 -0500 schrieb Yufei Yuan:
> Thanks for your time. It's my first time to do this, so I have been
> trying to follow literally on the wiki page to do it right. If you can
> elaborate a bit about what is broken? Is it the patch created
> incorrectly, or it is pasted incorrectly, or the style is still
> problematic?
> 
> I noticed that cutting and pasting from my console to the gmail
> compose window does not seem working alright. How do you normally do
> the inlining?
> 
> I have a full weekend to do this, and I do realize from the wiki page
> that it does not appear to be simple, :)
> 
> I now simply disable the footer, don't worry.

Just keep it on your decision. I'm not against to learn from the past.

It starts with lots of broken lines.

Cheers,
Hermann

> 
> Regards,
> 
> On Fri, Jun 19, 2009 at 7:41 PM, hermann pitton<hermann-pitton@arcor.de> wrote:
> >
> > Am Donnerstag, den 18.06.2009, 20:39 -0500 schrieb Yufei Yuan:
> >> This one is about the utility itself. I do apologize for the length
> >> here as "inline" patch is preferred according to the guide and I don't
> >> have any public online storage. Please let me know if this causes any
> >> inconvenience.
> >>
> >> Signed-off-by: Yufei Yuan <yfyuan@gmail.com>
> >>
> >> diff -uprN dvb-apps/util/atsc_epg/atsc_epg.c
> >> dvb-apps_new/util/atsc_epg/atsc_epg.c
> >> --- dvb-apps/util/atsc_epg/atsc_epg.c   1969-12-31 18:00:00.000000000
> >> -0600
> >> +++ dvb-apps_new/util/atsc_epg/atsc_epg.c       2009-06-18
> >> 20:17:24.527925142 -0500
> >> @@ -0,0 +1,1249 @@
> >> +/*
> >> + * atsc_epg utility
> >> + *
> >> + * Copyright (C) 2009 Yufei Yuan <yfyuan@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.
> >> + */
> >> +
> >> +#include <stdio.h>
> >> +#include <stdlib.h>
> >> +#include <unistd.h>
> >> +#include <string.h>
> >> +#include <time.h>
> >> +#include <signal.h>
> >> +#include <sys/types.h>
> >> +#include <sys/stat.h>
> >> +#include <fcntl.h>
> >> +#include <sys/ioctl.h>
> >> +#include <sys/poll.h>
> >> +#include <errno.h>
> >> +#include <getopt.h>
> >> +#include <stdarg.h>
> >> +#include <libdvbapi/dvbfe.h>
> >> +#include <libdvbapi/dvbdemux.h>
> >> +#include <libucsi/dvb/section.h>
> >> +#include <libucsi/atsc/section.h>
> >> +#include <libucsi/atsc/types.h>
> >> +
> >> +#define TIMEOUT                                60
> >> +#define RRT_TIMEOUT                    60
> >> +#define MAX_NUM_EVENT_TABLES           128
> >> +#define TITLE_BUFFER_LEN               4096
> >> +#define MESSAGE_BUFFER_LEN             (16 * 1024)
> >> +#define MAX_NUM_CHANNELS               16
> >> +#define MAX_NUM_EVENTS_PER_CHANNEL     (4 * 24 * 7)
> >> +
> >> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum
> >> atsc_section_tag tag,
> >> +       void **table_section);
> >> +
> >> +static const char *program;
> >> +static int adapter = 0;
> >> +static int period = 12; /* hours */
> >> +static int frequency;
> >> +static int enable_ett = 0;
> >> +static int ctrl_c = 0;
> >> +static const char *modulation = NULL;
> >> +static char separator[80];
> >> +void (*old_handler)(int);
> >> +
> >> +struct atsc_string_buffer {
> >> +       int buf_len;
> >> +       int buf_pos;
> >> +       char *string;
> >> +};
> >> +
> >> +struct atsc_event_info {
> >> +       uint16_t id;
> >> +       struct tm start;
> >> +       struct tm end;
> >> +       int title_pos;
> >> +       int title_len;
> >> +       int msg_pos;
> >> +       int msg_len;
> >> +};
> >> +
> >> +struct atsc_eit_section_info {
> >> +       uint8_t section_num;
> >> +       uint8_t num_events;
> >> +       uint8_t num_etms;
> >> +       uint8_t num_received_etms;
> >> +       struct atsc_event_info **events;
> >> +};
> >> +
> >> +struct atsc_eit_info {
> >> +       int num_eit_sections;
> >> +       struct atsc_eit_section_info *section;
> >> +};
> >> +
> >> +struct atsc_channel_info {
> >> +       uint8_t num_eits;
> >> +       uint8_t service_type;
> >> +       char short_name[8];
> >> +       uint16_t major_num;
> >> +       uint16_t minor_num;
> >> +       uint16_t tsid;
> >> +       uint16_t prog_num;
> >> +       uint16_t src_id;
> >> +       struct atsc_eit_info *eit;
> >> +       struct atsc_event_info *last_event;
> >> +       int event_info_index;
> >> +       struct atsc_event_info e[MAX_NUM_EVENTS_PER_CHANNEL];
> >> +       struct atsc_string_buffer title_buf;
> >> +       struct atsc_string_buffer msg_buf;
> >> +};
> >> +
> >> +struct atsc_virtual_channels_info {
> >> +       int num_channels;
> >> +       uint16_t eit_pid[MAX_NUM_EVENT_TABLES];
> >> +       uint16_t ett_pid[MAX_NUM_EVENT_TABLES];
> >> +       struct atsc_channel_info ch[MAX_NUM_CHANNELS];
> >> +} guide;
> >> +
> >> +struct mgt_table_name {
> >> +       uint16_t range;
> >> +       const char *string;
> >> +};
> >> +
> >> +struct mgt_table_name mgt_tab_name_array[] = {
> >> +       {0x0000, "terrestrial VCT with current_next_indictor=1"},
> >> +       {0x0001, "terrestrial VCT with current_next_indictor=0"},
> >> +       {0x0002, "cable VCT with current_next_indictor=1"},
> >> +       {0x0003, "cable VCT with current_next_indictor=0"},
> >> +       {0x0004, "channel ETT"},
> >> +       {0x0005, "DCCSCT"},
> >> +       {0x00FF, "reserved for future ATSC use"},
> >> +       {0x017F, "EIT"},
> >> +       {0x01FF, "reserved for future ATSC use"},
> >> +       {0x027F, "event ETT"},
> >> +       {0x02FF, "reserved for future ATSC use"}, /* FIXME */
> >> +       {0x03FF, "RRT with rating region"},
> >> +       {0x0FFF, "user private"},
> >> +       {0x13FF, "reserved for future ATSC use"},
> >> +       {0x14FF, "DCCT with dcc_id"},
> >> +       {0xFFFF, "reserved for future ATSC use"}
> >> +};
> >> +
> >> +const char *channel_modulation_mode[] = {
> >> +       "",
> >> +       "analog",
> >> +       "SCTE mode 1",
> >> +       "SCTE mode 2",
> >> +       "ATSC 8VSB",
> >> +       "ATSC 16VSB"
> >> +};
> >> +
> >> +const char *channel_service_type[] = {
> >> +       "",
> >> +       "analog TV",
> >> +       "ATSC digital TV",
> >> +       "ATSC audio",
> >> +       "ATSC data-only"
> >> +};
> >> +
> >> +void *(*table_callback[16])(struct atsc_section_psip *) =
> >> +{
> >> +       NULL, NULL, NULL, NULL, NULL, NULL, NULL,
> >> +       (void *(*)(struct atsc_section_psip *))atsc_mgt_section_codec,
> >> +       (void *(*)(struct atsc_section_psip
> >> *))atsc_tvct_section_codec,
> >> +       (void *(*)(struct atsc_section_psip
> >> *))atsc_cvct_section_codec,
> >> +       (void *(*)(struct atsc_section_psip *))atsc_rrt_section_codec,
> >> +       (void *(*)(struct atsc_section_psip *))atsc_eit_section_codec,
> >> +       (void *(*)(struct atsc_section_psip *))atsc_ett_section_codec,
> >> +       (void *(*)(struct atsc_section_psip *))atsc_stt_section_codec,
> >> +       NULL, NULL
> >> +};
> >> +
> >> +static void int_handler(int sig_num)
> >> +{
> >> +       if(SIGINT != sig_num) {
> >> +               return;
> >> +       }
> >> +       ctrl_c = 1;
> >> +}
> >> +
> >> +/* shamelessly stolen from dvbsnoop, but almost not modified */
> >> +static uint32_t get_bits(const uint8_t *buf, int startbit, int
> >> bitlen)
> >> +{
> >> +       const uint8_t *b;
> >> +       uint32_t mask,tmp_long;
> >> +       int bitHigh,i;
> >> +
> >> +       b = &buf[startbit / 8];
> >> +       startbit %= 8;
> >> +
> >> +       bitHigh = 8;
> >> +       tmp_long = b[0];
> >> +       for (i = 0; i < ((bitlen-1) >> 3); i++) {
> >> +               tmp_long <<= 8;
> >> +               tmp_long  |= b[i+1];
> >> +               bitHigh   += 8;
> >> +       }
> >> +
> >> +       startbit = bitHigh - startbit - bitlen;
> >> +       tmp_long = tmp_long >> startbit;
> >> +       mask     = (1ULL << bitlen) - 1;
> >> +       return tmp_long & mask;
> >> +}
> >> +
> >> +static void usage(void)
> >> +{
> >> +       fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p
> >> <period>]"
> >> +               " [-m <modulation>] [-t] [-h]\n", program);
> >> +}
> >> +
> >> +static void help(void)
> >> +{
> >> +       fprintf(stderr,
> >> +       "\nhelp:\n"
> >> +       "%s [-a <n>] -f <frequency> [-p <period>] [-m <modulation>]
> >> [-t] [-h]\n"
> >> +       "  -a: adapter index to use, (default 0)\n"
> >> +       "  -f: tuning frequency\n"
> >> +       "  -p: period in hours, (default 12)\n"
> >> +       "  -m: modulation ATSC vsb_8|vsb_16 (default vsb_8)\n"
> >> +       "  -t: enable ETT to receive program details, if available\n"
> >> +       "  -h: display this message\n", program);
> >> +}
> >> +
> >> +static int close_frontend(struct dvbfe_handle *fe)
> >> +{
> >> +       if(NULL == fe) {
> >> +               fprintf(stderr, "%s(): NULL pointer detected\n",
> >> __FUNCTION__);
> >> +       }
> >> +
> >> +       dvbfe_close(fe);
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int open_frontend(struct dvbfe_handle **fe)
> >> +{
> >> +       struct dvbfe_info fe_info;
> >> +
> >> +       if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
> >> +               fprintf(stderr, "%s(): error calling dvbfe_open()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +       dvbfe_get_info(*fe, 0, &fe_info,
> >> DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
> >> +       if(DVBFE_TYPE_ATSC != fe_info.type) {
> >> +               fprintf(stderr, "%s(): only ATSC frontend supported
> >> currently\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +       fe_info.feparams.frequency = frequency;
> >> +       fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
> >> +       fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
> >> +       fprintf(stdout, "tuning to %d Hz, please wait...\n",
> >> frequency);
> >> +       if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
> >> +               fprintf(stderr, "%s(): cannot lock to %d Hz in %d
> >> seconds\n",
> >> +                       __FUNCTION__, frequency, TIMEOUT);
> >> +               return -1;
> >> +       }
> >> +       fprintf(stdout, "tuner locked.\n");
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +#if ENABLE_RRT
> >> +/* this is untested as since this part of the library is broken */
> >> +static int parse_rrt(int dmxfd)
> >> +{
> >> +       const enum atsc_section_tag tag = stag_atsc_rating_region;
> >> +       struct atsc_rrt_section *rrt;
> >> +       struct atsc_text *region_name;
> >> +       struct atsc_text_string *atsc_str;
> >> +       int i, j, ret;
> >> +
> >> +       i = 0;
> >> +       fprintf(stdout, "waiting for RRT: ");
> >> +       fflush(stdout);
> >> +       while(i < RRT_TIMEOUT) {
> >> +               ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
> >> **)&rrt);
> >> +               if(0 > ret) {
> >> +                       fprintf(stderr, "%s(): error calling
> >> atsc_scan_table()\n",
> >> +                               __FUNCTION__);
> >> +                       return -1;
> >> +               }
> >> +               if(0 == ret) {
> >> +                       if(RRT_TIMEOUT > i) {
> >> +                               fprintf(stdout, ".");
> >> +                               fflush(stdout);
> >> +                       } else {
> >> +                               fprintf(stdout, "\nno RRT in %d
> >> seconds\n",
> >> +                                       RRT_TIMEOUT);
> >> +                               return 0;
> >> +                       }
> >> +                       i += TIMEOUT;
> >> +               } else {
> >> +                       fprintf(stdout, "\n");
> >> +                       fflush(stdout);
> >> +                       break;
> >> +               }
> >> +       }
> >> +
> >> +       region_name = atsc_rrt_section_rating_region_name_text(rrt);
> >> +       atsc_text_strings_for_each(region_name, atsc_str, i) {
> >> +               struct atsc_text_string_segment *seg;
> >> +
> >> +               atsc_text_string_segments_for_each(atsc_str, seg, j) {
> >> +                       const char *c;
> >> +                       int k;
> >> +                       if(seg->mode < 0x3E) {
> >> +                               fprintf(stderr, "%s(): text mode of
> >> 0x%02X "
> >> +                                       "not supported yet\n",
> >> +                                       __FUNCTION__, seg->mode);
> >> +                               return -1;
> >> +                       }
> >> +                       c = (const char
> >> *)atsc_text_string_segment_bytes(seg);
> >> +                       for(k = 0; k < seg->number_bytes; k++) {
> >> +                               fprintf(stdout, "%c", c[k]);
> >> +                       }
> >> +               }
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +#endif
> >> +
> >> +static int parse_stt(int dmxfd)
> >> +{
> >> +       const enum atsc_section_tag tag = stag_atsc_system_time;
> >> +       const struct atsc_stt_section *stt;
> >> +       time_t rx_time;
> >> +       time_t sys_time;
> >> +       int ret;
> >> +
> >> +       ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
> >> **)&stt);
> >> +       if(0 > ret) {
> >> +               fprintf(stderr, "%s(): error calling
> >> atsc_scan_table()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +       if(0 == ret) {
> >> +               fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
> >> +               return 0;
> >> +       }
> >> +
> >> +       rx_time = atsctime_to_unixtime(stt->system_time);
> >> +       time(&sys_time);
> >> +       fprintf(stdout, "system time: %s", ctime(&sys_time));
> >> +       fprintf(stdout, "TS STT time: %s", ctime(&rx_time));
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int parse_tvct(int dmxfd)
> >> +{
> >> +       int num_sections;
> >> +       uint32_t section_pattern;
> >> +       const enum atsc_section_tag tag =
> >> stag_atsc_terrestrial_virtual_channel;
> >> +       struct atsc_tvct_section *tvct;
> >> +       struct atsc_tvct_channel *ch;
> >> +       struct atsc_channel_info *curr_info;
> >> +       int i, k, ret;
> >> +
> >> +       section_pattern = 0;
> >> +       num_sections = -1;
> >> +
> >> +       do {
> >> +               ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
> >> **)&tvct);
> >> +               if(0 > ret) {
> >> +                       fprintf(stderr, "%s(): error calling
> >> atsc_scan_table()\n",
> >> +                       __FUNCTION__);
> >> +                       return -1;
> >> +               }
> >> +               if(0 == ret) {
> >> +                       fprintf(stdout, "no TVCT in %d seconds\n",
> >> TIMEOUT);
> >> +                       return 0;
> >> +               }
> >> +
> >> +               if(-1 == num_sections) {
> >> +                       num_sections = 1 +
> >> tvct->head.ext_head.last_section_number;
> >> +                       if(32 < num_sections) {
> >> +                               fprintf(stderr, "%s(): no support yet
> >> for "
> >> +                                       "tables having more than 32
> >> sections\n",
> >> +                                       __FUNCTION__);
> >> +                               return -1;
> >> +                       }
> >> +               } else {
> >> +                       if(num_sections !=
> >> +                               1 +
> >> tvct->head.ext_head.last_section_number) {
> >> +                               fprintf(stderr,
> >> +                                       "%s(): last section number
> >> does not match\n",
> >> +                                       __FUNCTION__);
> >> +                               return -1;
> >> +                       }
> >> +               }
> >> +               if(section_pattern & (1 <<
> >> tvct->head.ext_head.section_number)) {
> >> +                       continue;
> >> +               }
> >> +               section_pattern |= 1 <<
> >> tvct->head.ext_head.section_number;
> >> +
> >> +               if(MAX_NUM_CHANNELS < guide.num_channels +
> >> +                       tvct->num_channels_in_section) {
> >> +                       fprintf(stderr, "%s(): no support for more
> >> than %d "
> >> +                               "virtual channels in a pyhsical
> >> channel\n",
> >> +                               __FUNCTION__, MAX_NUM_CHANNELS);
> >> +                       return -1;
> >> +               }
> >> +               curr_info = &guide.ch[guide.num_channels];
> >> +               guide.num_channels += tvct->num_channels_in_section;
> >> +
> >> +       atsc_tvct_section_channels_for_each(tvct, ch, i) {
> >> +               /* initialize the curr_info structure */
> >> +               /* each EIT covers 3 hours */
> >> +               curr_info->num_eits = (period / 3) + !!(period % 3);
> >> +               while (curr_info->num_eits &&
> >> +                       (0xFFFF == guide.eit_pid[curr_info->num_eits -
> >> 1])) {
> >> +                       curr_info->num_eits -= 1;
> >> +               }
> >> +               if(curr_info->eit) {
> >> +                       fprintf(stderr, "%s(): non-NULL pointer
> >> detected "
> >> +                               "during initialization",
> >> __FUNCTION__);
> >> +                       return -1;
> >> +               }
> >> +               if(NULL == (curr_info->eit =
> >> calloc(curr_info->num_eits,
> >> +                       sizeof(struct atsc_eit_info)))) {
> >> +                       fprintf(stderr, "%s(): error calling
> >> calloc()\n",
> >> +                               __FUNCTION__);
> >> +                       return -1;
> >> +               }
> >> +               if(NULL == (curr_info->title_buf.string =
> >> calloc(TITLE_BUFFER_LEN,
> >> +                       sizeof(char)))) {
> >> +                       fprintf(stderr, "%s(): error calling
> >> calloc()\n",
> >> +                               __FUNCTION__);
> >> +                       return -1;
> >> +               }
> >> +               curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
> >> +               curr_info->title_buf.buf_pos = 0;
> >> +
> >> +               if(NULL == (curr_info->msg_buf.string =
> >> calloc(MESSAGE_BUFFER_LEN,
> >> +                       sizeof(char)))) {
> >> +                       fprintf(stderr, "%s(): error calling
> >> calloc()\n",
> >> +                               __FUNCTION__);
> >> +                       return -1;
> >> +               }
> >> +               curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
> >> +               curr_info->msg_buf.buf_pos = 0;
> >> +
> >> +               for(k = 0; k < 7; k++) {
> >> +                       curr_info->short_name[k] =
> >> +                               get_bits((const uint8_t
> >> *)ch->short_name,
> >> +                               k * 16, 16);
> >> +               }
> >> +               curr_info->service_type = ch->service_type;
> >> +               curr_info->major_num = ch->major_channel_number;
> >> +               curr_info->minor_num = ch->minor_channel_number;
> >> +               curr_info->tsid = ch->channel_TSID;
> >> +               curr_info->prog_num = ch->program_number;
> >> +               curr_info->src_id = ch->source_id;
> >> +               curr_info++;
> >> +               }
> >> +       } while(section_pattern != (uint32_t)((1 << num_sections) -
> >> 1));
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int match_event(struct atsc_eit_info *eit, uint16_t event_id,
> >> +       struct atsc_event_info **event, uint8_t *curr_index)
> >> +{
> >> +       int j, k;
> >> +       struct atsc_eit_section_info *section;
> >> +
> >> +       if(NULL == eit || NULL == event || NULL == curr_index) {
> >> +               fprintf(stderr, "%s(): NULL pointer detected\n",
> >> __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       for(j = 0; j < eit->num_eit_sections; j++) {
> >> +               section = &eit->section[j];
> >> +
> >> +               for(k = 0; k < section->num_events; k++) {
> >> +                       if(section->events[k] &&
> >> section->events[k]->id ==
> >> +                               event_id) {
> >> +                               *event = section->events[k];
> >> +                               break;
> >> +                       }
> >> +               }
> >> +               if(*event) {
> >> +                       *curr_index = j;
> >> +                       break;
> >> +               }
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int parse_message(struct atsc_channel_info *channel,
> >> +       struct atsc_ett_section *ett, struct atsc_event_info *event)
> >> +{
> >> +       int i, j;
> >> +       struct atsc_text *text;
> >> +       struct atsc_text_string *str;
> >> +
> >> +       if(NULL == ett || NULL == event || NULL == channel) {
> >> +               fprintf(stderr, "%s(): NULL pointer detected\n",
> >> __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       text = atsc_ett_section_extended_text_message(ett);
> >> +       atsc_text_strings_for_each(text, str, i) {
> >> +               struct atsc_text_string_segment *seg;
> >> +
> >> +               atsc_text_string_segments_for_each(str, seg, j) {
> >> +                       event->msg_pos = channel->msg_buf.buf_pos;
> >> +                       if(0 > atsc_text_segment_decode(seg,
> >> +                               (uint8_t **)&channel->msg_buf.string,
> >> +                               (size_t *)&channel->msg_buf.buf_len,
> >> +                               (size_t *)&channel->msg_buf.buf_pos))
> >> {
> >> +                               fprintf(stderr, "%s(): error calling "
> >> +
> >> "atsc_text_segment_decode()\n",
> >> +                                       __FUNCTION__);
> >> +                               return -1;
> >> +                       }
> >> +                       event->msg_len = 1 + channel->msg_buf.buf_pos
> >> -
> >> +                               event->msg_pos;
> >> +               }
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int parse_ett(int dmxfd, int index, uint16_t pid)
> >> +{
> >> +       uint8_t curr_index;
> >> +       uint32_t section_pattern;
> >> +       const enum atsc_section_tag tag = stag_atsc_extended_text;
> >> +       struct atsc_eit_info *eit;
> >> +       struct atsc_ett_section *ett;
> >> +       struct atsc_channel_info *channel;
> >> +       struct atsc_event_info *event;
> >> +       struct atsc_eit_section_info *section;
> >> +       uint16_t source_id, event_id;
> >> +       int c, ret;
> >> +
> >> +       if(0xFFFF == guide.ett_pid[index]) {
> >> +               return 0;
> >> +       }
> >> +
> >> +       for(c = 0; c < guide.num_channels; c++) {
> >> +               channel = &guide.ch[c];
> >> +               eit = &channel->eit[index];
> >> +
> >> +               section_pattern = 0;
> >> +               while(section_pattern !=
> >> +                       (uint32_t)((1 << eit->num_eit_sections) - 1))
> >> {
> >> +                       if(ctrl_c) {
> >> +                               return 0;
> >> +                       }
> >> +                       ret = atsc_scan_table(dmxfd, pid, tag, (void
> >> **)&ett);
> >> +                       fprintf(stdout, ".");
> >> +                       fflush(stdout);
> >> +                       if(0 > ret) {
> >> +                               fprintf(stderr, "%s(): error calling "
> >> +                                       "atsc_scan_table()\n",
> >> __FUNCTION__);
> >> +                               return -1;
> >> +                       }
> >> +                       if(0 == ret) {
> >> +                               fprintf(stdout, "no ETT %d in %d
> >> seconds\n",
> >> +                                       index, TIMEOUT);
> >> +                               return 0;
> >> +                       }
> >> +
> >> +                       source_id = ett->ETM_source_id;
> >> +                       event_id = ett->ETM_sub_id;
> >> +                       if(source_id != channel->src_id) {
> >> +                               continue;
> >> +                       }
> >> +
> >> +                       event = NULL;
> >> +                       if(match_event(eit, event_id, &event,
> >> &curr_index)) {
> >> +                               fprintf(stderr, "%s(): error calling "
> >> +                                       "match_event()\n",
> >> __FUNCTION__);
> >> +                               return -1;
> >> +                       }
> >> +                       if(NULL == event) {
> >> +                               continue;
> >> +                       }
> >> +                       if(section_pattern & (1 << curr_index)) {
> >> +                               /* the section has been filled, so
> >> skip,
> >> +                                * not consider version yet
> >> +                                */
> >> +                               continue;
> >> +                       }
> >> +                       if(event->msg_len) {
> >> +                               /* the message has been filled */
> >> +                               continue;
> >> +                       }
> >> +
> >> +                       if(parse_message(channel, ett, event)) {
> >> +                               fprintf(stderr, "%s(): error calling "
> >> +                                       "parse_message()\n",
> >> __FUNCTION__);
> >> +                               return -1;
> >> +                       }
> >> +                       section = &eit->section[curr_index];
> >> +                       if(++section->num_received_etms ==
> >> section->num_etms) {
> >> +                               section_pattern |= 1 << curr_index;
> >> +                       }
> >> +               }
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int parse_events(struct atsc_channel_info *curr_info,
> >> +       struct atsc_eit_section *eit, struct atsc_eit_section_info
> >> *section)
> >> +{
> >> +       int i, j, k;
> >> +       struct atsc_eit_event *e;
> >> +       time_t start_time, end_time;
> >> +
> >> +       if(NULL == curr_info || NULL == eit) {
> >> +               fprintf(stderr, "%s(): NULL pointer detected\n",
> >> __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       atsc_eit_section_events_for_each(eit, e, i) {
> >> +               struct atsc_text *title;
> >> +               struct atsc_text_string *str;
> >> +               struct atsc_event_info *e_info =
> >> +                       &curr_info->e[curr_info->event_info_index];
> >> +
> >> +               if(0 == i && curr_info->last_event) {
> >> +                       if(e->event_id == curr_info->last_event->id) {
> >> +                               section->events[i] = NULL;
> >> +                               /* skip if it's the same event
> >> spanning
> >> +                                * over sections
> >> +                                */
> >> +                               continue;
> >> +                       }
> >> +               }
> >> +               curr_info->event_info_index += 1;
> >> +               section->events[i] = e_info;
> >> +               e_info->id = e->event_id;
> >> +               start_time = atsctime_to_unixtime(e->start_time);
> >> +               end_time = start_time + e->length_in_seconds;
> >> +               localtime_r(&start_time, &e_info->start);
> >> +               localtime_r(&end_time, &e_info->end);
> >> +               if(0 != e->ETM_location && 3 != e->ETM_location) {
> >> +                       /* FIXME assume 1 and 2 is interchangable as
> >> of now */
> >> +                       section->num_etms++;
> >> +               }
> >> +
> >> +               title = atsc_eit_event_name_title_text(e);
> >> +               atsc_text_strings_for_each(title, str, j) {
> >> +                       struct atsc_text_string_segment *seg;
> >> +
> >> +                       atsc_text_string_segments_for_each(str, seg,
> >> k) {
> >> +                               e_info->title_pos =
> >> curr_info->title_buf.buf_pos;
> >> +                               if(0 > atsc_text_segment_decode(seg,
> >> +                                       (uint8_t
> >> **)&curr_info->title_buf.string,
> >> +                                       (size_t
> >> *)&curr_info->title_buf.buf_len,
> >> +                                       (size_t
> >> *)&curr_info->title_buf.buf_pos)) {
> >> +                                       fprintf(stderr, "%s(): error
> >> calling "
> >> +
> >> "atsc_text_segment_decode()\n",
> >> +                                               __FUNCTION__);
> >> +                                       return -1;
> >> +                               }
> >> +                               e_info->title_len =
> >> curr_info->title_buf.buf_pos -
> >> +                                       e_info->title_pos + 1;
> >> +                       }
> >> +               }
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int parse_eit(int dmxfd, int index, uint16_t pid)
> >> +{
> >> +       int num_sections;
> >> +       uint8_t section_num;
> >> +       uint8_t curr_channel_index;
> >> +       uint32_t section_pattern;
> >> +       const enum atsc_section_tag tag = stag_atsc_event_information;
> >> +       struct atsc_eit_section *eit;
> >> +       struct atsc_channel_info *curr_info;
> >> +       struct atsc_eit_info *eit_info;
> >> +       struct atsc_eit_section_info *section;
> >> +       uint16_t source_id;
> >> +       uint32_t eit_instance_pattern = 0;
> >> +       int i, k, ret;
> >> +
> >> +       while(eit_instance_pattern !=
> >> +               (uint32_t)((1 << guide.num_channels) - 1)) {
> >> +               source_id = 0xFFFF;
> >> +               section_pattern = 0;
> >> +               num_sections = -1;
> >> +
> >> +               do {
> >> +                       ret = atsc_scan_table(dmxfd, pid, tag, (void
> >> **)&eit);
> >> +                       fprintf(stdout, ".");
> >> +                       fflush(stdout);
> >> +                       if(0 > ret) {
> >> +                               fprintf(stderr, "%s(): error calling "
> >> +                                       "atsc_scan_table()\n",
> >> __FUNCTION__);
> >> +                               return -1;
> >> +                       }
> >> +                       if(0 == ret) {
> >> +                               fprintf(stdout, "no EIT %d in %d
> >> seconds\n",
> >> +                                       index, TIMEOUT);
> >> +                               return 0;
> >> +                       }
> >> +
> >> +                       if(0xFFFF == source_id) {
> >> +                       source_id = atsc_eit_section_source_id(eit);
> >> +                       for(k = 0; k < guide.num_channels; k++) {
> >> +                               if(source_id == guide.ch[k].src_id) {
> >> +                                       curr_info = &guide.ch[k];
> >> +                                       curr_channel_index = k;
> >> +                                       if(0 == index) {
> >> +                                               curr_info->last_event
> >> = NULL;
> >> +                                       }
> >> +                                       break;
> >> +                               }
> >> +                       }
> >> +                       if(k == guide.num_channels) {
> >> +                               fprintf(stderr, "%s(): cannot find
> >> source_id "
> >> +                                       "0x%04X in the EIT\n",
> >> +                                       __FUNCTION__, source_id);
> >> +                               return -1;
> >> +                       }
> >> +                       } else {
> >> +                               if(source_id !=
> >> +
> >> atsc_eit_section_source_id(eit)) {
> >> +                                       continue;
> >> +                               }
> >> +                       }
> >> +                       if(eit_instance_pattern & (1 <<
> >> curr_channel_index)) {
> >> +                               /* we have received this instance,
> >> +                                * so quit quick
> >> +                                */
> >> +                               break;
> >> +                       }
> >> +
> >> +                       if(-1 == num_sections) {
> >> +                               num_sections = 1 +
> >> +
> >> eit->head.ext_head.last_section_number;
> >> +                               if(32 < num_sections) {
> >> +                                       fprintf(stderr,
> >> +                                               "%s(): no support yet
> >> for "
> >> +                                               "tables having more
> >> than "
> >> +                                               "32 sections\n",
> >> __FUNCTION__);
> >> +                                       return -1;
> >> +                               }
> >> +                       } else {
> >> +                               if(num_sections != 1 +
> >> +
> >> eit->head.ext_head.last_section_number) {
> >> +                                       fprintf(stderr,
> >> +                                               "%s(): last section
> >> number "
> >> +                                               "does not match\n",
> >> +                                               __FUNCTION__);
> >> +                                       return -1;
> >> +                               }
> >> +                       }
> >> +                       if(section_pattern &
> >> +                               (1 <<
> >> eit->head.ext_head.section_number)) {
> >> +                               continue;
> >> +                       }
> >> +                       section_pattern |= 1 <<
> >> eit->head.ext_head.section_number;
> >> +
> >> +                       eit_info = &curr_info->eit[index];
> >> +                       if(NULL == (eit_info->section =
> >> +                               realloc(eit_info->section,
> >> +                               (eit_info->num_eit_sections + 1) *
> >> +                               sizeof(struct
> >> atsc_eit_section_info)))) {
> >> +                               fprintf(stderr,
> >> +                                       "%s(): error calling
> >> realloc()\n",
> >> +                                       __FUNCTION__);
> >> +                               return -1;
> >> +                       }
> >> +                       section_num =
> >> eit->head.ext_head.section_number;
> >> +                       if(0 == eit_info->num_eit_sections) {
> >> +                               eit_info->num_eit_sections = 1;
> >> +                               section = eit_info->section;
> >> +                       } else {
> >> +                               /* have to sort it into section order
> >> +                                * (temporal order)
> >> +                                */
> >> +                               for(i = 0; i <
> >> eit_info->num_eit_sections; i++) {
> >> +
> >> if(eit_info->section[i].section_num >
> >> +                                               section_num) {
> >> +                                               break;
> >> +                                       }
> >> +                               }
> >> +                               memmove(&eit_info->section[i + 1],
> >> +                                       &eit_info->section[i],
> >> +                                       (eit_info->num_eit_sections -
> >> i) *
> >> +                                       sizeof(struct
> >> atsc_eit_section_info));
> >> +                               section = &eit_info->section[i - 1];
> >> +                               section = &eit_info->section[i];
> >> +                               eit_info->num_eit_sections += 1;
> >> +                       }
> >> +
> >> +                       section->section_num = section_num;
> >> +                       section->num_events =
> >> eit->num_events_in_section;
> >> +                       section->num_etms = 0;
> >> +                       section->num_received_etms = 0;
> >> +                       if(NULL == (section->events =
> >> calloc(section->num_events,
> >> +                               sizeof(struct atsc_event_info *)))) {
> >> +                               fprintf(stderr, "%s(): error calling
> >> calloc()\n",
> >> +                                       __FUNCTION__);
> >> +                               return -1;
> >> +                       }
> >> +                       if(parse_events(curr_info, eit, section)) {
> >> +                               fprintf(stderr, "%s(): error calling "
> >> +                                       "parse_events()\n",
> >> __FUNCTION__);
> >> +                               return -1;
> >> +                       }
> >> +               } while(section_pattern != (uint32_t)((1 <<
> >> num_sections) - 1));
> >> +               eit_instance_pattern |= 1 << curr_channel_index;
> >> +       }
> >> +
> >> +       for(i = 0; i < guide.num_channels; i++) {
> >> +               struct atsc_channel_info *channel = &guide.ch[i];
> >> +               struct atsc_eit_info *ei = &channel->eit[index];
> >> +               struct atsc_eit_section_info *s;
> >> +
> >> +               if(0 == ei->num_eit_sections) {
> >> +                       channel->last_event = NULL;
> >> +                       continue;
> >> +               }
> >> +               s = &ei->section[ei->num_eit_sections - 1];
> >> +               /* BUG: it's incorrect when last section has no event
> >> */
> >> +               if(0 == s->num_events) {
> >> +                       channel->last_event = NULL;
> >> +                       continue;
> >> +               }
> >> +               channel->last_event = s->events[s->num_events - 1];
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int parse_mgt(int dmxfd)
> >> +{
> >> +       const enum atsc_section_tag tag = stag_atsc_master_guide;
> >> +       struct atsc_mgt_section *mgt;
> >> +       struct atsc_mgt_table *t;
> >> +       int i, j, ret;
> >> +
> >> +       ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void
> >> **)&mgt);
> >> +       if(0 > ret) {
> >> +               fprintf(stderr, "%s(): error calling
> >> atsc_scan_table()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +       if(0 == ret) {
> >> +               fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
> >> +               return 0;
> >> +       }
> >> +
> >> +       fprintf(stdout, "MGT table:\n");
> >> +       atsc_mgt_section_tables_for_each(mgt, t, i) {
> >> +               struct mgt_table_name table;
> >> +
> >> +       for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
> >> +               sizeof(struct mgt_table_name)); j++) {
> >> +               if(t->table_type > mgt_tab_name_array[j].range) {
> >> +                       continue;
> >> +               }
> >> +               table = mgt_tab_name_array[j];
> >> +               if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
> >> +                       mgt_tab_name_array[j].range) {
> >> +                       j = -1;
> >> +               } else {
> >> +                       j = t->table_type - mgt_tab_name_array[j -
> >> 1].range - 1;
> >> +                       if(0x017F == table.range) {
> >> +                               guide.eit_pid[j] = t->table_type_PID;
> >> +                       } else if (0x027F == table.range) {
> >> +                               guide.ett_pid[j] = t->table_type_PID;
> >> +                       }
> >> +               }
> >> +               break;
> >> +       }
> >> +
> >> +               fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X,
> >> %s", i,
> >> +                   t->table_type, t->table_type_PID, table.string);
> >> +               if(-1 != j) {
> >> +                   fprintf(stdout, " %d", j);
> >> +               }
> >> +               fprintf(stdout, "\n");
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int cleanup_guide(void)
> >> +{
> >> +       int i, j, k;
> >> +
> >> +       for(i = 0; i < guide.num_channels; i++) {
> >> +               struct atsc_channel_info *channel = &guide.ch[i];
> >> +
> >> +               if(channel->title_buf.string) {
> >> +                       free(channel->title_buf.string);
> >> +               }
> >> +               if(channel->msg_buf.string) {
> >> +                       free(channel->msg_buf.string);
> >> +               }
> >> +               for(j = 0; j < channel->num_eits; j++) {
> >> +                       struct atsc_eit_info *eit = &channel->eit[j];
> >> +
> >> +                       for(k = 0; k < eit->num_eit_sections; k++) {
> >> +                               struct atsc_eit_section_info *section
> >> =
> >> +                                       &eit->section[k];
> >> +                               if(section->num_events) {
> >> +                                       free(section->events);
> >> +                               }
> >> +                       }
> >> +                       if(k) {
> >> +                               free(eit->section);
> >> +                       }
> >> +               }
> >> +               if(j) {
> >> +                       free(channel->eit);
> >> +               }
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int print_events(struct atsc_channel_info *channel,
> >> +       struct atsc_eit_section_info *section)
> >> +{
> >> +       int m;
> >> +       char line[256];
> >> +
> >> +       if(NULL == section) {
> >> +               fprintf(stderr, "%s(): NULL pointer detected",
> >> __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +       for(m = 0; m < section->num_events; m++) {
> >> +               struct atsc_event_info *event =
> >> +                       section->events[m];
> >> +
> >> +               if(NULL == event) {
> >> +                       continue;
> >> +               }
> >> +               fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
> >> +                       event->start.tm_hour, event->start.tm_min,
> >> +                       event->end.tm_hour, event->end.tm_min);
> >> +               snprintf(line, event->title_len, "%s",
> >> +                       &channel->title_buf.string[event->title_pos]);
> >> +               line[event->title_len] = '\0';
> >> +               fprintf(stdout, "%s\n", line);
> >> +               if(event->msg_len) {
> >> +                       int len = event->msg_len;
> >> +                       int pos = event->msg_pos;
> >> +                       size_t part;
> >> +
> >> +                       do {
> >> +                               part = len > 255 ? 255 : len;
> >> +                               snprintf(line, part, "%s",
> >> +
> >> &channel->msg_buf.string[pos]);
> >> +                               line[part] = '\0';
> >> +                               fprintf(stdout, "%s", line);
> >> +                               len -= part;
> >> +                               pos += part;
> >> +                       } while(0 < len);
> >> +                       fprintf(stdout, "\n");
> >> +               }
> >> +       }
> >> +       return 0;
> >> +}
> >> +
> >> +static int print_guide(void)
> >> +{
> >> +       int i, j, k;
> >> +
> >> +       fprintf(stdout, "%s\n", separator);
> >> +       for(i = 0; i < guide.num_channels; i++) {
> >> +               struct atsc_channel_info *channel = &guide.ch[i];
> >> +
> >> +               fprintf(stdout, "%d.%d  %s\n", channel->major_num,
> >> +                       channel->minor_num, channel->short_name);
> >> +               for(j = 0; j < channel->num_eits; j++) {
> >> +                       struct atsc_eit_info *eit = &channel->eit[j];
> >> +
> >> +                       for(k = 0; k < eit->num_eit_sections; k++) {
> >> +                               struct atsc_eit_section_info *section
> >> =
> >> +                                       &eit->section[k];
> >> +                               if(print_events(channel, section)) {
> >> +                                       fprintf(stderr, "%s(): error
> >> calling "
> >> +                                               "print_events()\n",
> >> __FUNCTION__);
> >> +                                       return -1;
> >> +                               }
> >> +                       }
> >> +               }
> >> +               fprintf(stdout, "%s\n", separator);
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int open_demux(int *dmxfd)
> >> +{
> >> +       if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
> >> +               fprintf(stderr, "%s(): error calling
> >> dvbdemux_open_demux()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +       return 0;
> >> +}
> >> +
> >> +static int close_demux(int dmxfd)
> >> +{
> >> +       if(dvbdemux_stop(dmxfd)) {
> >> +               fprintf(stderr, "%s(): error calling
> >> dvbdemux_stop()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +       return 0;
> >> +}
> >> +
> >> +/* used other utilities as template and generalized here */
> >> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum
> >> atsc_section_tag tag,
> >> +       void **table_section)
> >> +{
> >> +       uint8_t filter[18];
> >> +       uint8_t mask[18];
> >> +       unsigned char sibuf[4096];
> >> +       int size;
> >> +       int ret;
> >> +       struct pollfd pollfd;
> >> +       struct section *section;
> >> +       struct section_ext *section_ext;
> >> +       struct atsc_section_psip *psip;
> >> +
> >> +       /* create a section filter for the table */
> >> +       memset(filter, 0, sizeof(filter));
> >> +       memset(mask, 0, sizeof(mask));
> >> +       filter[0] = tag;
> >> +       mask[0] = 0xFF;
> >> +       if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1,
> >> 1)) {
> >> +               fprintf(stderr, "%s(): error calling
> >> atsc_scan_table()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       /* poll for data */
> >> +       pollfd.fd = dmxfd;
> >> +       pollfd.events = POLLIN | POLLERR |POLLPRI;
> >> +       if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
> >> +               if(ctrl_c) {
> >> +                       return 0;
> >> +               }
> >> +               fprintf(stderr, "%s(): error calling poll()\n",
> >> __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       if(0 == ret) {
> >> +               return 0;
> >> +       }
> >> +
> >> +       /* read it */
> >> +       if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
> >> +               fprintf(stderr, "%s(): error calling read()\n",
> >> __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       /* parse section */
> >> +       section = section_codec(sibuf, size);
> >> +       if(NULL == section) {
> >> +               fprintf(stderr, "%s(): error calling
> >> section_codec()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       section_ext = section_ext_decode(section, 0);
> >> +       if(NULL == section_ext) {
> >> +               fprintf(stderr, "%s(): error calling
> >> section_ext_decode()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       psip = atsc_section_psip_decode(section_ext);
> >> +       if(NULL == psip) {
> >> +               fprintf(stderr,
> >> +                       "%s(): error calling
> >> atsc_section_psip_decode()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       *table_section = table_callback[tag & 0x0F](psip);
> >> +       if(NULL == *table_section) {
> >> +               fprintf(stderr, "%s(): error decode table section\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       return 1;
> >> +}
> >> +
> >> +int main(int argc, char *argv[])
> >> +{
> >> +       int i, dmxfd;
> >> +       struct dvbfe_handle *fe;
> >> +
> >> +       program = argv[0];
> >> +
> >> +       if(1 == argc) {
> >> +               usage();
> >> +               exit(-1);
> >> +       }
> >> +
> >> +       for( ; ; ) {
> >> +               char c;
> >> +
> >> +               if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
> >> +                       break;
> >> +               }
> >> +
> >> +               switch(c) {
> >> +               case 'a':
> >> +                       adapter = strtoll(optarg, NULL, 0);
> >> +                       break;
> >> +
> >> +               case 'f':
> >> +                       frequency = strtol(optarg, NULL, 0);
> >> +                       break;
> >> +
> >> +               case 'p':
> >> +                       period = strtol(optarg, NULL, 0);
> >> +                       /* each table covers 3 hours */
> >> +                       if((3 * MAX_NUM_EVENT_TABLES) < period) {
> >> +                               period = 3 * MAX_NUM_EVENT_TABLES;
> >> +                       }
> >> +                       break;
> >> +
> >> +               case 'm':
> >> +                       /* just stub, so far ATSC only has VSB_8 */
> >> +                       modulation = optarg;
> >> +                       break;
> >> +
> >> +               case 't':
> >> +                       enable_ett = 1;
> >> +                       break;
> >> +
> >> +               case 'h':
> >> +                       help();
> >> +                       exit(0);
> >> +
> >> +               default:
> >> +                       usage();
> >> +                       exit(-1);
> >> +               }
> >> +       }
> >> +
> >> +       memset(separator, '-', sizeof(separator));
> >> +       separator[79] = '\0';
> >> +       memset(&guide, 0, sizeof(struct atsc_virtual_channels_info));
> >> +       memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES *
> >> sizeof(uint16_t));
> >> +       memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES *
> >> sizeof(uint16_t));
> >> +
> >> +       if(open_frontend(&fe)) {
> >> +               fprintf(stderr, "%s(): error calling
> >> open_frontend()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       if(open_demux(&dmxfd)) {
> >> +               fprintf(stderr, "%s(): error calling open_demux()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       if(parse_stt(dmxfd)) {
> >> +               fprintf(stderr, "%s(): error calling parse_stt()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       if(parse_mgt(dmxfd)) {
> >> +               fprintf(stderr, "%s(): error calling parse_mgt()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       if(parse_tvct(dmxfd)) {
> >> +               fprintf(stderr, "%s(): error calling parse_tvct()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +#ifdef ENABLE_RRT
> >> +       if(parse_rrt(dmxfd)) {
> >> +               fprintf(stderr, "%s(): error calling parse_rrt()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +#endif
> >> +
> >> +       fprintf(stdout, "receiving EIT ");
> >> +       for(i = 0; i < guide.ch[0].num_eits; i++) {
> >> +               if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
> >> +                       fprintf(stderr, "%s(): error calling
> >> parse_eit()\n",
> >> +                               __FUNCTION__);
> >> +                       return -1;
> >> +               }
> >> +       }
> >> +       fprintf(stdout, "\n");
> >> +
> >> +       old_handler = signal(SIGINT, int_handler);
> >> +       if(enable_ett) {
> >> +               fprintf(stdout, "receiving ETT ");
> >> +               for(i = 0; i < guide.ch[0].num_eits; i++) {
> >> +                       if(0xFFFF != guide.ett_pid[i]) {
> >> +                               if(parse_ett(dmxfd, i,
> >> guide.ett_pid[i])) {
> >> +                                       fprintf(stderr, "%s(): error
> >> calling "
> >> +                                               "parse_eit()\n",
> >> __FUNCTION__);
> >> +                                       return -1;
> >> +                               }
> >> +                       }
> >> +                       if(ctrl_c) {
> >> +                               break;
> >> +                       }
> >> +               }
> >> +               fprintf(stdout, "\n");
> >> +       }
> >> +       signal(SIGINT, old_handler);
> >> +
> >> +       if(print_guide()) {
> >> +               fprintf(stderr, "%s(): error calling print_guide()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       if(cleanup_guide()) {
> >> +               fprintf(stderr, "%s(): error calling
> >> cleanup_guide()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       if(close_demux(dmxfd)) {
> >> +               fprintf(stderr, "%s(): error calling close_demux()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       if(close_frontend(fe)) {
> >> +               fprintf(stderr, "%s(): error calling close_demux()\n",
> >> +                       __FUNCTION__);
> >> +               return -1;
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> diff -uprN dvb-apps/util/atsc_epg/Makefile
> >> dvb-apps_new/util/atsc_epg/Makefile
> >> --- dvb-apps/util/atsc_epg/Makefile     1969-12-31 18:00:00.000000000
> >> -0600
> >> +++ dvb-apps_new/util/atsc_epg/Makefile 2009-06-18 20:11:58.362985962
> >> -0500
> >> @@ -0,0 +1,16 @@
> >> +# Makefile for linuxtv.org dvb-apps/util/atsc_epg
> >> +
> >> +binaries = atsc_epg
> >> +
> >> +inst_bin = $(binaries)
> >> +
> >> +CPPFLAGS += -I../../lib -std=c99 -D_POSIX_SOURCE
> >> +#LDFLAGS  += -static -L../../lib/libdvbapi -L../../lib/libucsi
> >> +LDFLAGS  += -L../../lib/libdvbapi -L../../lib/libucsi
> >> +LDLIBS   += -ldvbapi -lucsi
> >> +
> >> +.PHONY: all
> >> +
> >> +all: $(binaries)
> >> +
> >> +include ../../Make.rules
> >> diff -uprN dvb-apps/util/atsc_epg/README dvb-apps_new/util/atsc_epg/README
> >> --- dvb-apps/util/atsc_epg/README       1969-12-31 18:00:00.000000000 -0600
> >> +++ dvb-apps_new/util/atsc_epg/README   2009-06-18 20:33:47.836924378 -0500
> >> @@ -0,0 +1,12 @@
> >> +Hi there,
> >> +
> >> +atsc_epg is a small utility for obtaining information such as programs, EPG
> >> +(electronic program guide) from an ATSC channel.
> >> +
> >> +Pulling the detailed information, i.e., option '-t', may take fairly long
> >> +time, or never ending, which is a bug of the PSIP generator. Ctrl+C can be
> >> +used to abort and the received parts will be printed.
> >> +
> >> +Enjoy,
> >> +Yufei
> >> +
> >> diff -uprN dvb-apps/util/Makefile dvb-apps_new/util/Makefile
> >> --- dvb-apps/util/Makefile      2009-06-18 19:43:30.034986539 -0500
> >> +++ dvb-apps_new/util/Makefile  2009-06-18 20:11:41.169986806 -0500
> >> @@ -3,6 +3,7 @@
> >>  .PHONY: all clean install
> >>
> >>  all clean install:
> >> +       $(MAKE) -C atsc_epg $@
> >>         $(MAKE) -C av7110_loadkeys $@
> >>         $(MAKE) -C dib3000-watch $@
> >>         $(MAKE) -C dst-utils $@
> >>
> >
> > --
> > Even uttering "HI" or "HAO" is offensive, sometime, somewhere. Reader
> > discretion is advised.
> > --
> >
> > My, the patch is still pretty well broken.
> >
> > I leave it to Manu to help you further in the submission procedures ;)
> >
> > As said, keep your Confucius stuff if you like.
> >
> > I won't rant a second time on it.
> >
> > But don't ever complain here, if others do have some good arguments too,
> > in their footers ...
> >
> > Cheers,
> > Hermann
> >
> >
> >
> >
> >
> >
> >
> >
> >


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-20  1:28               ` hermann pitton
@ 2009-06-20  2:38                 ` Yufei Yuan
  2009-06-20  3:04                   ` hermann pitton
  0 siblings, 1 reply; 22+ messages in thread
From: Yufei Yuan @ 2009-06-20  2:38 UTC (permalink / raw)
  To: hermann pitton; +Cc: Manu Abraham, Linux Media Mailing List

Ok, let me first summarize what I have done in order not to waste your time again. I used Evolution client, 
used preformatted option, sent it to my other email box, forwarded it back and saved it as text file, then
patched the original tree, so far everything looks okay. Hopefully you guys can do start to do next step.

I do apologize for your wasted time.

Signed-off-by: Yufei Yuan <yfyuan@gmail.com>

diff -uprN dvb-apps/util/atsc_epg/atsc_epg.c dvb-apps_new/util/atsc_epg/atsc_epg.c
--- dvb-apps/util/atsc_epg/atsc_epg.c	1969-12-31 18:00:00.000000000 -0600
+++ dvb-apps_new/util/atsc_epg/atsc_epg.c	2009-06-19 20:31:17.710924970 -0500
@@ -0,0 +1,1249 @@
+/*
+ * atsc_epg utility
+ *
+ * Copyright (C) 2009 Yufei Yuan <yfyuan@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <libdvbapi/dvbfe.h>
+#include <libdvbapi/dvbdemux.h>
+#include <libucsi/dvb/section.h>
+#include <libucsi/atsc/section.h>
+#include <libucsi/atsc/types.h>
+
+#define TIMEOUT				60
+#define RRT_TIMEOUT			60
+#define MAX_NUM_EVENT_TABLES		128
+#define TITLE_BUFFER_LEN		4096
+#define MESSAGE_BUFFER_LEN		(16 * 1024)
+#define MAX_NUM_CHANNELS		16
+#define MAX_NUM_EVENTS_PER_CHANNEL	(4 * 24 * 7)
+
+static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
+	void **table_section);
+
+static const char *program;
+static int adapter = 0;
+static int period = 12; /* hours */
+static int frequency;
+static int enable_ett = 0;
+static int ctrl_c = 0;
+static const char *modulation = NULL;
+static char separator[80];
+void (*old_handler)(int);
+
+struct atsc_string_buffer {
+	int buf_len;
+	int buf_pos;
+	char *string;
+};
+
+struct atsc_event_info {
+	uint16_t id;
+	struct tm start;
+	struct tm end;
+	int title_pos;
+	int title_len;
+	int msg_pos;
+	int msg_len;
+};
+
+struct atsc_eit_section_info {
+	uint8_t section_num;
+	uint8_t num_events;
+	uint8_t num_etms;
+	uint8_t num_received_etms;
+	struct atsc_event_info **events;
+};
+
+struct atsc_eit_info {
+	int num_eit_sections;
+	struct atsc_eit_section_info *section;
+};
+
+struct atsc_channel_info {
+	uint8_t num_eits;
+	uint8_t service_type;
+	char short_name[8];
+	uint16_t major_num;
+	uint16_t minor_num;
+	uint16_t tsid;
+	uint16_t prog_num;
+	uint16_t src_id;
+	struct atsc_eit_info *eit;
+	struct atsc_event_info *last_event;
+	int event_info_index;
+	struct atsc_event_info e[MAX_NUM_EVENTS_PER_CHANNEL];
+	struct atsc_string_buffer title_buf;
+	struct atsc_string_buffer msg_buf;
+};
+
+struct atsc_virtual_channels_info {
+	int num_channels;
+	uint16_t eit_pid[MAX_NUM_EVENT_TABLES];
+	uint16_t ett_pid[MAX_NUM_EVENT_TABLES];
+	struct atsc_channel_info ch[MAX_NUM_CHANNELS];
+} guide;
+
+struct mgt_table_name {
+	uint16_t range;
+	const char *string;
+};
+
+struct mgt_table_name mgt_tab_name_array[] = {
+	{0x0000, "terrestrial VCT with current_next_indictor=1"},
+	{0x0001, "terrestrial VCT with current_next_indictor=0"},
+	{0x0002, "cable VCT with current_next_indictor=1"},
+	{0x0003, "cable VCT with current_next_indictor=0"},
+	{0x0004, "channel ETT"},
+	{0x0005, "DCCSCT"},
+	{0x00FF, "reserved for future ATSC use"},
+	{0x017F, "EIT"},
+	{0x01FF, "reserved for future ATSC use"},
+	{0x027F, "event ETT"},
+	{0x02FF, "reserved for future ATSC use"}, /* FIXME */
+	{0x03FF, "RRT with rating region"},
+	{0x0FFF, "user private"},
+	{0x13FF, "reserved for future ATSC use"},
+	{0x14FF, "DCCT with dcc_id"},
+	{0xFFFF, "reserved for future ATSC use"}
+};
+
+const char *channel_modulation_mode[] = {
+	"",
+	"analog",
+	"SCTE mode 1",
+	"SCTE mode 2",
+	"ATSC 8VSB",
+	"ATSC 16VSB"
+};
+
+const char *channel_service_type[] = {
+	"",
+	"analog TV",
+	"ATSC digital TV",
+	"ATSC audio",
+	"ATSC data-only"
+};
+
+void *(*table_callback[16])(struct atsc_section_psip *) =
+{
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	(void *(*)(struct atsc_section_psip *))atsc_mgt_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_tvct_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_cvct_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_rrt_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_eit_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_ett_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_stt_section_codec,
+	NULL, NULL
+};
+
+static void int_handler(int sig_num)
+{
+	if(SIGINT != sig_num) {
+		return;
+	}
+	ctrl_c = 1;
+}
+
+/* shamelessly stolen from dvbsnoop, but almost not modified */
+static uint32_t get_bits(const uint8_t *buf, int startbit, int bitlen)
+{
+	const uint8_t *b;
+	uint32_t mask,tmp_long;
+	int bitHigh,i;
+
+	b = &buf[startbit / 8];
+	startbit %= 8;
+
+	bitHigh = 8;
+	tmp_long = b[0];
+	for (i = 0; i < ((bitlen-1) >> 3); i++) {
+		tmp_long <<= 8;
+		tmp_long  |= b[i+1];
+		bitHigh   += 8;
+	}
+
+	startbit = bitHigh - startbit - bitlen;
+	tmp_long = tmp_long >> startbit;
+	mask     = (1ULL << bitlen) - 1;
+	return tmp_long & mask;
+}
+
+static void usage(void)
+{
+	fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p <period>]"
+		" [-m <modulation>] [-t] [-h]\n", program);
+}
+
+static void help(void)
+{
+	fprintf(stderr,
+	"\nhelp:\n"
+	"%s [-a <n>] -f <frequency> [-p <period>] [-m <modulation>] [-t] [-h]\n"
+	"  -a: adapter index to use, (default 0)\n"
+	"  -f: tuning frequency\n"
+	"  -p: period in hours, (default 12)\n"
+	"  -m: modulation ATSC vsb_8|vsb_16 (default vsb_8)\n"
+	"  -t: enable ETT to receive program details, if available\n"
+	"  -h: display this message\n", program);
+}
+
+static int close_frontend(struct dvbfe_handle *fe)
+{
+	if(NULL == fe) {
+		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+	}
+
+	dvbfe_close(fe);
+
+	return 0;
+}
+
+static int open_frontend(struct dvbfe_handle **fe)
+{
+	struct dvbfe_info fe_info;
+
+	if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
+		fprintf(stderr, "%s(): error calling dvbfe_open()\n",
+			__FUNCTION__);
+		return -1;
+	}
+	dvbfe_get_info(*fe, 0, &fe_info, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
+	if(DVBFE_TYPE_ATSC != fe_info.type) {
+		fprintf(stderr, "%s(): only ATSC frontend supported currently\n",
+			__FUNCTION__);
+		return -1;
+	}
+	fe_info.feparams.frequency = frequency;
+	fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
+	fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
+	fprintf(stdout, "tuning to %d Hz, please wait...\n", frequency);
+	if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
+		fprintf(stderr, "%s(): cannot lock to %d Hz in %d seconds\n",
+			__FUNCTION__, frequency, TIMEOUT);
+		return -1;
+	}
+	fprintf(stdout, "tuner locked.\n");
+
+	return 0;
+}
+
+#ifdef ENABLE_RRT
+/* this is untested as since this part of the library is broken */
+static int parse_rrt(int dmxfd)
+{
+	const enum atsc_section_tag tag = stag_atsc_rating_region;
+	struct atsc_rrt_section *rrt;
+	struct atsc_text *region_name;
+	struct atsc_text_string *atsc_str;
+	int i, j, ret;
+
+	i = 0;
+	fprintf(stdout, "waiting for RRT: ");
+	fflush(stdout);
+	while(i < RRT_TIMEOUT) {
+		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&rrt);
+		if(0 > ret) {
+			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
+				__FUNCTION__);
+			return -1;
+		}
+		if(0 == ret) {
+			if(RRT_TIMEOUT > i) {
+				fprintf(stdout, ".");
+				fflush(stdout);
+			} else {
+				fprintf(stdout, "\nno RRT in %d seconds\n",
+					RRT_TIMEOUT);
+				return 0;
+			}
+			i += TIMEOUT;
+		} else {
+			fprintf(stdout, "\n");
+			fflush(stdout);
+			break;
+		}
+	}
+
+	region_name = atsc_rrt_section_rating_region_name_text(rrt);
+	atsc_text_strings_for_each(region_name, atsc_str, i) {
+		struct atsc_text_string_segment *seg;
+
+		atsc_text_string_segments_for_each(atsc_str, seg, j) {
+			const char *c;
+			int k;
+			if(seg->mode < 0x3E) {
+				fprintf(stderr, "%s(): text mode of 0x%02X "
+					"not supported yet\n",
+					__FUNCTION__, seg->mode);
+				return -1;
+			}
+			c = (const char *)atsc_text_string_segment_bytes(seg);
+			for(k = 0; k < seg->number_bytes; k++) {
+				fprintf(stdout, "%c", c[k]);
+			}
+		}
+	}
+
+	return 0;
+}
+#endif
+
+static int parse_stt(int dmxfd)
+{
+	const enum atsc_section_tag tag = stag_atsc_system_time;
+	const struct atsc_stt_section *stt;
+	time_t rx_time;
+	time_t sys_time;
+	int ret;
+
+	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&stt);
+	if(0 > ret) {
+		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
+			__FUNCTION__);
+		return -1;
+	}
+	if(0 == ret) {
+		fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
+		return 0;
+	}
+
+	rx_time = atsctime_to_unixtime(stt->system_time);
+	time(&sys_time);
+	fprintf(stdout, "system time: %s", ctime(&sys_time));
+	fprintf(stdout, "TS STT time: %s", ctime(&rx_time));
+
+	return 0;
+}
+
+static int parse_tvct(int dmxfd)
+{
+	int num_sections;
+	uint32_t section_pattern;
+	const enum atsc_section_tag tag = stag_atsc_terrestrial_virtual_channel;
+	struct atsc_tvct_section *tvct;
+	struct atsc_tvct_channel *ch;
+	struct atsc_channel_info *curr_info;
+	int i, k, ret;
+
+	section_pattern = 0;
+	num_sections = -1;
+
+	do {
+		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&tvct);
+		if(0 > ret) {
+			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
+			__FUNCTION__);
+			return -1;
+		}
+		if(0 == ret) {
+			fprintf(stdout, "no TVCT in %d seconds\n", TIMEOUT);
+			return 0;
+		}
+
+		if(-1 == num_sections) {
+			num_sections = 1 + tvct->head.ext_head.last_section_number;
+			if(32 < num_sections) {
+				fprintf(stderr, "%s(): no support yet for "
+					"tables having more than 32 sections\n",
+					__FUNCTION__);
+				return -1;
+			}
+		} else {
+			if(num_sections !=
+				1 + tvct->head.ext_head.last_section_number) {
+				fprintf(stderr,
+					"%s(): last section number does not match\n",
+					__FUNCTION__);
+				return -1;
+			}
+		}
+		if(section_pattern & (1 << tvct->head.ext_head.section_number)) {
+			continue;
+		}
+		section_pattern |= 1 << tvct->head.ext_head.section_number;
+
+		if(MAX_NUM_CHANNELS < guide.num_channels +
+			tvct->num_channels_in_section) {
+			fprintf(stderr, "%s(): no support for more than %d "
+				"virtual channels in a pyhsical channel\n",
+				__FUNCTION__, MAX_NUM_CHANNELS);
+			return -1;
+		}
+		curr_info = &guide.ch[guide.num_channels];
+		guide.num_channels += tvct->num_channels_in_section;
+
+	atsc_tvct_section_channels_for_each(tvct, ch, i) {
+		/* initialize the curr_info structure */
+		/* each EIT covers 3 hours */
+		curr_info->num_eits = (period / 3) + !!(period % 3);
+		while (curr_info->num_eits &&
+			(0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
+			curr_info->num_eits -= 1;
+		}
+		if(curr_info->eit) {
+			fprintf(stderr, "%s(): non-NULL pointer detected "
+				"during initialization", __FUNCTION__);
+			return -1;
+		}
+		if(NULL == (curr_info->eit = calloc(curr_info->num_eits,
+			sizeof(struct atsc_eit_info)))) {
+			fprintf(stderr, "%s(): error calling calloc()\n",
+				__FUNCTION__);
+			return -1;
+		}
+		if(NULL == (curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN,
+			sizeof(char)))) {
+			fprintf(stderr, "%s(): error calling calloc()\n",
+				__FUNCTION__);
+			return -1;
+		}
+		curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
+		curr_info->title_buf.buf_pos = 0;
+
+		if(NULL == (curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN,
+			sizeof(char)))) {
+			fprintf(stderr, "%s(): error calling calloc()\n",
+				__FUNCTION__);
+			return -1;
+		}
+		curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
+		curr_info->msg_buf.buf_pos = 0;
+
+		for(k = 0; k < 7; k++) {
+			curr_info->short_name[k] =
+				get_bits((const uint8_t *)ch->short_name,
+				k * 16, 16);
+		}
+		curr_info->service_type = ch->service_type;
+		curr_info->major_num = ch->major_channel_number;
+		curr_info->minor_num = ch->minor_channel_number;
+		curr_info->tsid = ch->channel_TSID;
+		curr_info->prog_num = ch->program_number;
+		curr_info->src_id = ch->source_id;
+		curr_info++;
+		}
+	} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
+
+	return 0;
+}
+
+static int match_event(struct atsc_eit_info *eit, uint16_t event_id,
+	struct atsc_event_info **event, uint8_t *curr_index)
+{
+	int j, k;
+	struct atsc_eit_section_info *section;
+
+	if(NULL == eit || NULL == event || NULL == curr_index) {
+		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+		return -1;
+	}
+
+	for(j = 0; j < eit->num_eit_sections; j++) {
+		section = &eit->section[j];
+
+		for(k = 0; k < section->num_events; k++) {
+			if(section->events[k] && section->events[k]->id ==
+				event_id) {
+				*event = section->events[k];
+				break;
+			}
+		}
+		if(*event) {
+			*curr_index = j;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int parse_message(struct atsc_channel_info *channel,
+	struct atsc_ett_section *ett, struct atsc_event_info *event)
+{
+	int i, j;
+	struct atsc_text *text;
+	struct atsc_text_string *str;
+
+	if(NULL == ett || NULL == event || NULL == channel) {
+		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+		return -1;
+	}
+
+	text = atsc_ett_section_extended_text_message(ett);
+	atsc_text_strings_for_each(text, str, i) {
+		struct atsc_text_string_segment *seg;
+
+		atsc_text_string_segments_for_each(str, seg, j) {
+			event->msg_pos = channel->msg_buf.buf_pos;
+			if(0 > atsc_text_segment_decode(seg,
+				(uint8_t **)&channel->msg_buf.string,
+				(size_t *)&channel->msg_buf.buf_len,
+				(size_t *)&channel->msg_buf.buf_pos)) {
+				fprintf(stderr, "%s(): error calling "
+					"atsc_text_segment_decode()\n",
+					__FUNCTION__);
+				return -1;
+			}
+			event->msg_len = channel->msg_buf.buf_pos -
+				event->msg_pos;
+		}
+	}
+
+	return 0;
+}
+
+static int parse_ett(int dmxfd, int index, uint16_t pid)
+{
+	uint8_t curr_index;
+	uint32_t section_pattern;
+	const enum atsc_section_tag tag = stag_atsc_extended_text;
+	struct atsc_eit_info *eit;
+	struct atsc_ett_section *ett;
+	struct atsc_channel_info *channel;
+	struct atsc_event_info *event;
+	struct atsc_eit_section_info *section;
+	uint16_t source_id, event_id;
+	int c, ret;
+
+	if(0xFFFF == guide.ett_pid[index]) {
+		return 0;
+	}
+
+	for(c = 0; c < guide.num_channels; c++) {
+		channel = &guide.ch[c];
+		eit = &channel->eit[index];
+
+		section_pattern = 0;
+		while(section_pattern !=
+			(uint32_t)((1 << eit->num_eit_sections) - 1)) {
+			if(ctrl_c) {
+				return 0;
+			}
+			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&ett);
+			fprintf(stdout, ".");
+			fflush(stdout);
+			if(0 > ret) {
+				fprintf(stderr, "%s(): error calling "
+					"atsc_scan_table()\n", __FUNCTION__);
+				return -1;
+			}
+			if(0 == ret) {
+				fprintf(stdout, "no ETT %d in %d seconds\n",
+					index, TIMEOUT);
+				return 0;
+			}
+
+			source_id = ett->ETM_source_id;
+			event_id = ett->ETM_sub_id;
+			if(source_id != channel->src_id) {
+				continue;
+			}
+
+			event = NULL;
+			if(match_event(eit, event_id, &event, &curr_index)) {
+				fprintf(stderr, "%s(): error calling "
+					"match_event()\n", __FUNCTION__);
+				return -1;
+			}
+			if(NULL == event) {
+				continue;
+			}
+			if(section_pattern & (1 << curr_index)) {
+				/* the section has been filled, so skip,
+				 * not consider version yet
+				 */
+				continue;
+			}
+			if(event->msg_len) {
+				/* the message has been filled */
+				continue;
+			}
+
+			if(parse_message(channel, ett, event)) {
+				fprintf(stderr, "%s(): error calling "
+					"parse_message()\n", __FUNCTION__);
+				return -1;
+			}
+			section = &eit->section[curr_index];
+			if(++section->num_received_etms == section->num_etms) {
+				section_pattern |= 1 << curr_index;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int parse_events(struct atsc_channel_info *curr_info,
+	struct atsc_eit_section *eit, struct atsc_eit_section_info *section)
+{
+	int i, j, k;
+	struct atsc_eit_event *e;
+	time_t start_time, end_time;
+
+	if(NULL == curr_info || NULL == eit) {
+		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+		return -1;
+	}
+
+	atsc_eit_section_events_for_each(eit, e, i) {
+		struct atsc_text *title;
+		struct atsc_text_string *str;
+		struct atsc_event_info *e_info =
+			&curr_info->e[curr_info->event_info_index];
+
+		if(0 == i && curr_info->last_event) {
+			if(e->event_id == curr_info->last_event->id) {
+				section->events[i] = NULL;
+				/* skip if it's the same event spanning
+				 * over sections
+				 */
+				continue;
+			}
+		}
+		curr_info->event_info_index += 1;
+		section->events[i] = e_info;
+		e_info->id = e->event_id;
+		start_time = atsctime_to_unixtime(e->start_time);
+		end_time = start_time + e->length_in_seconds;
+		localtime_r(&start_time, &e_info->start);
+		localtime_r(&end_time, &e_info->end);
+		if(0 != e->ETM_location && 3 != e->ETM_location) {
+			/* FIXME assume 1 and 2 is interchangable as of now */
+			section->num_etms++;
+		}
+
+		title = atsc_eit_event_name_title_text(e);
+		atsc_text_strings_for_each(title, str, j) {
+			struct atsc_text_string_segment *seg;
+
+			atsc_text_string_segments_for_each(str, seg, k) {
+				e_info->title_pos = curr_info->title_buf.buf_pos;
+				if(0 > atsc_text_segment_decode(seg,
+					(uint8_t **)&curr_info->title_buf.string,
+					(size_t *)&curr_info->title_buf.buf_len,
+					(size_t *)&curr_info->title_buf.buf_pos)) {
+					fprintf(stderr, "%s(): error calling "
+						"atsc_text_segment_decode()\n",
+						__FUNCTION__);
+					return -1;
+				}
+				e_info->title_len = curr_info->title_buf.buf_pos -
+					e_info->title_pos + 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int parse_eit(int dmxfd, int index, uint16_t pid)
+{
+	int num_sections;
+	uint8_t section_num;
+	uint8_t curr_channel_index;
+	uint32_t section_pattern;
+	const enum atsc_section_tag tag = stag_atsc_event_information;
+	struct atsc_eit_section *eit;
+	struct atsc_channel_info *curr_info;
+	struct atsc_eit_info *eit_info;
+	struct atsc_eit_section_info *section;
+	uint16_t source_id;
+	uint32_t eit_instance_pattern = 0;
+	int i, k, ret;
+
+	while(eit_instance_pattern !=
+		(uint32_t)((1 << guide.num_channels) - 1)) {
+		source_id = 0xFFFF;
+		section_pattern = 0;
+		num_sections = -1;
+
+		do {
+			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&eit);
+			fprintf(stdout, ".");
+			fflush(stdout);
+			if(0 > ret) {
+				fprintf(stderr, "%s(): error calling "
+					"atsc_scan_table()\n", __FUNCTION__);
+				return -1;
+			}
+			if(0 == ret) {
+				fprintf(stdout, "no EIT %d in %d seconds\n",
+					index, TIMEOUT);
+				return 0;
+			}
+
+			if(0xFFFF == source_id) {
+			source_id = atsc_eit_section_source_id(eit);
+			for(k = 0; k < guide.num_channels; k++) {
+				if(source_id == guide.ch[k].src_id) {
+					curr_info = &guide.ch[k];
+					curr_channel_index = k;
+					if(0 == index) {
+						curr_info->last_event = NULL;
+					}
+					break;
+				}
+			}
+			if(k == guide.num_channels) {
+				fprintf(stderr, "%s(): cannot find source_id "
+					"0x%04X in the EIT\n",
+					__FUNCTION__, source_id);
+				return -1;
+			}
+			} else {
+				if(source_id !=
+					atsc_eit_section_source_id(eit)) {
+					continue;
+				}
+			}
+			if(eit_instance_pattern & (1 << curr_channel_index)) {
+				/* we have received this instance,
+				 * so quit quick
+				 */
+				break;
+			}
+
+			if(-1 == num_sections) {
+				num_sections = 1 +
+					eit->head.ext_head.last_section_number;
+				if(32 < num_sections) {
+					fprintf(stderr,
+						"%s(): no support yet for "
+						"tables having more than "
+						"32 sections\n", __FUNCTION__);
+					return -1;
+				}
+			} else {
+				if(num_sections != 1 +
+					eit->head.ext_head.last_section_number) {
+					fprintf(stderr,
+						"%s(): last section number "
+						"does not match\n",
+						__FUNCTION__);
+					return -1;
+				}
+			}
+			if(section_pattern &
+				(1 << eit->head.ext_head.section_number)) {
+				continue;
+			}
+			section_pattern |= 1 << eit->head.ext_head.section_number;
+
+			eit_info = &curr_info->eit[index];
+			if(NULL == (eit_info->section =
+				realloc(eit_info->section,
+				(eit_info->num_eit_sections + 1) *
+				sizeof(struct atsc_eit_section_info)))) {
+				fprintf(stderr,
+					"%s(): error calling realloc()\n",
+					__FUNCTION__);
+				return -1;
+			}
+			section_num = eit->head.ext_head.section_number;
+			if(0 == eit_info->num_eit_sections) {
+				eit_info->num_eit_sections = 1;
+				section = eit_info->section;
+			} else {
+				/* have to sort it into section order
+				 * (temporal order)
+				 */
+				for(i = 0; i < eit_info->num_eit_sections; i++) {
+					if(eit_info->section[i].section_num >
+						section_num) {
+						break;
+					}
+				}
+				memmove(&eit_info->section[i + 1],
+					&eit_info->section[i],
+					(eit_info->num_eit_sections - i) *
+					sizeof(struct atsc_eit_section_info));
+				section = &eit_info->section[i - 1];
+				section = &eit_info->section[i];
+				eit_info->num_eit_sections += 1;
+			}
+
+			section->section_num = section_num;
+			section->num_events = eit->num_events_in_section;
+			section->num_etms = 0;
+			section->num_received_etms = 0;
+			if(NULL == (section->events = calloc(section->num_events,
+				sizeof(struct atsc_event_info *)))) {
+				fprintf(stderr, "%s(): error calling calloc()\n",
+					__FUNCTION__);
+				return -1;
+			}
+			if(parse_events(curr_info, eit, section)) {
+				fprintf(stderr, "%s(): error calling "
+					"parse_events()\n", __FUNCTION__);
+				return -1;
+			}
+		} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
+		eit_instance_pattern |= 1 << curr_channel_index;
+	}
+
+	for(i = 0; i < guide.num_channels; i++) {
+		struct atsc_channel_info *channel = &guide.ch[i];
+		struct atsc_eit_info *ei = &channel->eit[index];
+		struct atsc_eit_section_info *s;
+
+		if(0 == ei->num_eit_sections) {
+			channel->last_event = NULL;
+			continue;
+		}
+		s = &ei->section[ei->num_eit_sections - 1];
+		/* BUG: it's incorrect when last section has no event */
+		if(0 == s->num_events) {
+			channel->last_event = NULL;
+			continue;
+		}
+		channel->last_event = s->events[s->num_events - 1];
+	}
+
+	return 0;
+}
+
+static int parse_mgt(int dmxfd)
+{
+	const enum atsc_section_tag tag = stag_atsc_master_guide;
+	struct atsc_mgt_section *mgt;
+	struct atsc_mgt_table *t;
+	int i, j, ret;
+
+	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&mgt);
+	if(0 > ret) {
+		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
+			__FUNCTION__);
+		return -1;
+	}
+	if(0 == ret) {
+		fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
+		return 0;
+	}
+
+	fprintf(stdout, "MGT table:\n");
+	atsc_mgt_section_tables_for_each(mgt, t, i) {
+		struct mgt_table_name table;
+
+	for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
+		sizeof(struct mgt_table_name)); j++) {
+		if(t->table_type > mgt_tab_name_array[j].range) {
+			continue;
+		}
+		table = mgt_tab_name_array[j];
+		if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
+			mgt_tab_name_array[j].range) {
+			j = -1;
+		} else {
+			j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
+			if(0x017F == table.range) {
+				guide.eit_pid[j] = t->table_type_PID;
+			} else if (0x027F == table.range) {
+				guide.ett_pid[j] = t->table_type_PID;
+			}
+		}
+		break;
+	}
+
+		fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X, %s", i,
+			t->table_type, t->table_type_PID, table.string);
+		if(-1 != j) {
+			fprintf(stdout, " %d", j);
+		}
+		fprintf(stdout, "\n");
+	}
+
+	return 0;
+}
+
+static int cleanup_guide(void)
+{
+	int i, j, k;
+
+	for(i = 0; i < guide.num_channels; i++) {
+		struct atsc_channel_info *channel = &guide.ch[i];
+
+		if(channel->title_buf.string) {
+			free(channel->title_buf.string);
+		}
+		if(channel->msg_buf.string) {
+			free(channel->msg_buf.string);
+		}
+		for(j = 0; j < channel->num_eits; j++) {
+			struct atsc_eit_info *eit = &channel->eit[j];
+
+			for(k = 0; k < eit->num_eit_sections; k++) {
+				struct atsc_eit_section_info *section =
+					&eit->section[k];
+				if(section->num_events) {
+					free(section->events);
+				}
+			}
+			if(k) {
+				free(eit->section);
+			}
+		}
+		if(j) {
+			free(channel->eit);
+		}
+	}
+
+	return 0;
+}
+
+static int print_events(struct atsc_channel_info *channel,
+	struct atsc_eit_section_info *section)
+{
+	int m;
+	char line[256];
+
+	if(NULL == section) {
+		fprintf(stderr, "%s(): NULL pointer detected", __FUNCTION__);
+		return -1;
+	}
+	for(m = 0; m < section->num_events; m++) {
+		struct atsc_event_info *event =
+			section->events[m];
+
+		if(NULL == event) {
+			continue;
+		}
+		fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
+			event->start.tm_hour, event->start.tm_min,
+			event->end.tm_hour, event->end.tm_min);
+		snprintf(line, event->title_len, "%s",
+			&channel->title_buf.string[event->title_pos]);
+		line[event->title_len] = '\0';
+		fprintf(stdout, "%s\n", line);
+		if(event->msg_len) {
+			int len = event->msg_len;
+			int pos = event->msg_pos;
+			size_t part;
+
+			do {
+				part = len > 255 ? 255 : len;
+				snprintf(line, part + 1, "%s",
+					&channel->msg_buf.string[pos]);
+				line[part] = '\0';
+				fprintf(stdout, "%s", line);
+				len -= part;
+				pos += part;
+			} while(0 < len);
+			fprintf(stdout, "\n");
+		}
+	}
+	return 0;
+}
+
+static int print_guide(void)
+{
+	int i, j, k;
+
+	fprintf(stdout, "%s\n", separator);
+	for(i = 0; i < guide.num_channels; i++) {
+		struct atsc_channel_info *channel = &guide.ch[i];
+
+		fprintf(stdout, "%d.%d  %s\n", channel->major_num,
+			channel->minor_num, channel->short_name);
+		for(j = 0; j < channel->num_eits; j++) {
+			struct atsc_eit_info *eit = &channel->eit[j];
+
+			for(k = 0; k < eit->num_eit_sections; k++) {
+				struct atsc_eit_section_info *section =
+					&eit->section[k];
+				if(print_events(channel, section)) {
+					fprintf(stderr, "%s(): error calling "
+						"print_events()\n", __FUNCTION__);
+					return -1;
+				}
+			}
+		}
+		fprintf(stdout, "%s\n", separator);
+	}
+
+	return 0;
+}
+
+static int open_demux(int *dmxfd)
+{
+	if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
+		fprintf(stderr, "%s(): error calling dvbdemux_open_demux()\n",
+			__FUNCTION__);
+		return -1;
+	}
+	return 0;
+}
+
+static int close_demux(int dmxfd)
+{
+	if(dvbdemux_stop(dmxfd)) {
+		fprintf(stderr, "%s(): error calling dvbdemux_stop()\n",
+			__FUNCTION__);
+		return -1;
+	}
+	return 0;
+}
+
+/* used other utilities as template and generalized here */
+static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
+	void **table_section)
+{
+	uint8_t filter[18];
+	uint8_t mask[18];
+	unsigned char sibuf[4096];
+	int size;
+	int ret;
+	struct pollfd pollfd;
+	struct section *section;
+	struct section_ext *section_ext;
+	struct atsc_section_psip *psip;
+
+	/* create a section filter for the table */
+	memset(filter, 0, sizeof(filter));
+	memset(mask, 0, sizeof(mask));
+	filter[0] = tag;
+	mask[0] = 0xFF;
+	if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
+		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	/* poll for data */
+	pollfd.fd = dmxfd;
+	pollfd.events = POLLIN | POLLERR |POLLPRI;
+	if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
+		if(ctrl_c) {
+			return 0;
+		}
+		fprintf(stderr, "%s(): error calling poll()\n", __FUNCTION__);
+		return -1;
+	}
+
+	if(0 == ret) {
+		return 0;
+	}
+
+	/* read it */
+	if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
+		fprintf(stderr, "%s(): error calling read()\n", __FUNCTION__);
+		return -1;
+	}
+
+	/* parse section */
+	section = section_codec(sibuf, size);
+	if(NULL == section) {
+		fprintf(stderr, "%s(): error calling section_codec()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	section_ext = section_ext_decode(section, 0);
+	if(NULL == section_ext) {
+		fprintf(stderr, "%s(): error calling section_ext_decode()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	psip = atsc_section_psip_decode(section_ext);
+	if(NULL == psip) {
+		fprintf(stderr,
+			"%s(): error calling atsc_section_psip_decode()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	*table_section = table_callback[tag & 0x0F](psip);
+	if(NULL == *table_section) {
+		fprintf(stderr, "%s(): error decode table section\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	int i, dmxfd;
+	struct dvbfe_handle *fe;
+
+	program = argv[0];
+
+	if(1 == argc) {
+		usage();
+		exit(-1);
+	}
+
+	for( ; ; ) {
+		char c;
+
+		if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
+			break;
+		}
+
+		switch(c) {
+		case 'a':
+			adapter = strtoll(optarg, NULL, 0);
+			break;
+
+		case 'f':
+			frequency = strtol(optarg, NULL, 0);
+			break;
+
+		case 'p':
+			period = strtol(optarg, NULL, 0);
+			/* each table covers 3 hours */
+			if((3 * MAX_NUM_EVENT_TABLES) < period) {
+				period = 3 * MAX_NUM_EVENT_TABLES;
+			}
+			break;
+
+		case 'm':
+			/* just stub, so far ATSC only has VSB_8 */
+			modulation = optarg;
+			break;
+
+		case 't':
+			enable_ett = 1;
+			break;
+
+		case 'h':
+			help();
+			exit(0);
+
+		default:
+			usage();
+			exit(-1);
+		}
+	}
+
+	memset(separator, '-', sizeof(separator));
+	separator[79] = '\0';
+	memset(&guide, 0, sizeof(struct atsc_virtual_channels_info));
+	memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
+	memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
+
+	if(open_frontend(&fe)) {
+		fprintf(stderr, "%s(): error calling open_frontend()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(open_demux(&dmxfd)) {
+		fprintf(stderr, "%s(): error calling open_demux()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(parse_stt(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_stt()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(parse_mgt(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_mgt()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(parse_tvct(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_tvct()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+#ifdef ENABLE_RRT
+	if(parse_rrt(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_rrt()\n",
+			__FUNCTION__);
+		return -1;
+	}
+#endif
+
+	fprintf(stdout, "receiving EIT ");
+	for(i = 0; i < guide.ch[0].num_eits; i++) {
+		if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
+			fprintf(stderr, "%s(): error calling parse_eit()\n",
+				__FUNCTION__);
+			return -1;
+		}
+	}
+	fprintf(stdout, "\n");
+
+	old_handler = signal(SIGINT, int_handler);
+	if(enable_ett) {
+		fprintf(stdout, "receiving ETT ");
+		for(i = 0; i < guide.ch[0].num_eits; i++) {
+			if(0xFFFF != guide.ett_pid[i]) {
+				if(parse_ett(dmxfd, i, guide.ett_pid[i])) {
+					fprintf(stderr, "%s(): error calling "
+						"parse_eit()\n", __FUNCTION__);
+					return -1;
+				}
+			}
+			if(ctrl_c) {
+				break;
+			}
+		}
+		fprintf(stdout, "\n");
+	}
+	signal(SIGINT, old_handler);
+
+	if(print_guide()) {
+		fprintf(stderr, "%s(): error calling print_guide()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(cleanup_guide()) {
+		fprintf(stderr, "%s(): error calling cleanup_guide()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(close_demux(dmxfd)) {
+		fprintf(stderr, "%s(): error calling close_demux()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(close_frontend(fe)) {
+		fprintf(stderr, "%s(): error calling close_demux()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	return 0;
+}
diff -uprN dvb-apps/util/atsc_epg/Makefile dvb-apps_new/util/atsc_epg/Makefile
--- dvb-apps/util/atsc_epg/Makefile	1969-12-31 18:00:00.000000000 -0600
+++ dvb-apps_new/util/atsc_epg/Makefile	2009-06-18 20:11:58.362985962 -0500
@@ -0,0 +1,16 @@
+# Makefile for linuxtv.org dvb-apps/util/atsc_epg
+
+binaries = atsc_epg
+
+inst_bin = $(binaries)
+
+CPPFLAGS += -I../../lib -std=c99 -D_POSIX_SOURCE
+#LDFLAGS  += -static -L../../lib/libdvbapi -L../../lib/libucsi
+LDFLAGS  += -L../../lib/libdvbapi -L../../lib/libucsi
+LDLIBS   += -ldvbapi -lucsi
+
+.PHONY: all
+
+all: $(binaries)
+
+include ../../Make.rules
diff -uprN dvb-apps/util/atsc_epg/README dvb-apps_new/util/atsc_epg/README
--- dvb-apps/util/atsc_epg/README	1969-12-31 18:00:00.000000000 -0600
+++ dvb-apps_new/util/atsc_epg/README	2009-06-18 20:33:47.836924378 -0500
@@ -0,0 +1,12 @@
+Hi there,
+
+atsc_epg is a small utility for obtaining information such as programs, EPG 
+(electronic program guide) from an ATSC channel. 
+
+Pulling the detailed information, i.e., option '-t', may take fairly long 
+time, or never ending, which is a bug of the PSIP generator. Ctrl+C can be 
+used to abort and the received parts will be printed.
+
+Enjoy,
+Yufei
+
diff -uprN dvb-apps/util/Makefile dvb-apps_new/util/Makefile
--- dvb-apps/util/Makefile	2009-06-18 19:43:30.034986539 -0500
+++ dvb-apps_new/util/Makefile	2009-06-18 20:11:41.169986806 -0500
@@ -3,6 +3,7 @@
 .PHONY: all clean install
 
 all clean install:
+	$(MAKE) -C atsc_epg $@
 	$(MAKE) -C av7110_loadkeys $@
 	$(MAKE) -C dib3000-watch $@
 	$(MAKE) -C dst-utils $@


On Sat, 2009-06-20 at 03:28 +0200, hermann pitton wrote: 
> Hi,
> 
> Am Freitag, den 19.06.2009, 20:00 -0500 schrieb Yufei Yuan:
> > Thanks for your time. It's my first time to do this, so I have been
> > trying to follow literally on the wiki page to do it right. If you can
> > elaborate a bit about what is broken? Is it the patch created
> > incorrectly, or it is pasted incorrectly, or the style is still
> > problematic?
> > 
> > I noticed that cutting and pasting from my console to the gmail
> > compose window does not seem working alright. How do you normally do
> > the inlining?
> > 
> > I have a full weekend to do this, and I do realize from the wiki page
> > that it does not appear to be simple, :)
> > 
> > I now simply disable the footer, don't worry.
> 
> Just keep it on your decision. I'm not against to learn from the past.
> 
> It starts with lots of broken lines.
> 
> Cheers,
> Hermann



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-20  2:38                 ` Yufei Yuan
@ 2009-06-20  3:04                   ` hermann pitton
  0 siblings, 0 replies; 22+ messages in thread
From: hermann pitton @ 2009-06-20  3:04 UTC (permalink / raw)
  To: yfyuan; +Cc: Manu Abraham, Linux Media Mailing List


Am Freitag, den 19.06.2009, 21:38 -0500 schrieb Yufei Yuan:
> Ok, let me first summarize what I have done in order not to waste your time again. I used Evolution client, 
> used preformatted option, sent it to my other email box, forwarded it back and saved it as text file, then
> patched the original tree, so far everything looks okay. Hopefully you guys can do start to do next step.
> 
> I do apologize for your wasted time.
> 
> Signed-off-by: Yufei Yuan <yfyuan@gmail.com>

Manu,

please review.

Hermann

> 
> diff -uprN dvb-apps/util/atsc_epg/atsc_epg.c dvb-apps_new/util/atsc_epg/atsc_epg.c
> --- dvb-apps/util/atsc_epg/atsc_epg.c	1969-12-31 18:00:00.000000000 -0600
> +++ dvb-apps_new/util/atsc_epg/atsc_epg.c	2009-06-19 20:31:17.710924970 -0500
> @@ -0,0 +1,1249 @@
> +/*
> + * atsc_epg utility
> + *
> + * Copyright (C) 2009 Yufei Yuan <yfyuan@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <time.h>
> +#include <signal.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <sys/ioctl.h>
> +#include <sys/poll.h>
> +#include <errno.h>
> +#include <getopt.h>
> +#include <stdarg.h>
> +#include <libdvbapi/dvbfe.h>
> +#include <libdvbapi/dvbdemux.h>
> +#include <libucsi/dvb/section.h>
> +#include <libucsi/atsc/section.h>
> +#include <libucsi/atsc/types.h>
> +
> +#define TIMEOUT				60
> +#define RRT_TIMEOUT			60
> +#define MAX_NUM_EVENT_TABLES		128
> +#define TITLE_BUFFER_LEN		4096
> +#define MESSAGE_BUFFER_LEN		(16 * 1024)
> +#define MAX_NUM_CHANNELS		16
> +#define MAX_NUM_EVENTS_PER_CHANNEL	(4 * 24 * 7)
> +
> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
> +	void **table_section);
> +
> +static const char *program;
> +static int adapter = 0;
> +static int period = 12; /* hours */
> +static int frequency;
> +static int enable_ett = 0;
> +static int ctrl_c = 0;
> +static const char *modulation = NULL;
> +static char separator[80];
> +void (*old_handler)(int);
> +
> +struct atsc_string_buffer {
> +	int buf_len;
> +	int buf_pos;
> +	char *string;
> +};
> +
> +struct atsc_event_info {
> +	uint16_t id;
> +	struct tm start;
> +	struct tm end;
> +	int title_pos;
> +	int title_len;
> +	int msg_pos;
> +	int msg_len;
> +};
> +
> +struct atsc_eit_section_info {
> +	uint8_t section_num;
> +	uint8_t num_events;
> +	uint8_t num_etms;
> +	uint8_t num_received_etms;
> +	struct atsc_event_info **events;
> +};
> +
> +struct atsc_eit_info {
> +	int num_eit_sections;
> +	struct atsc_eit_section_info *section;
> +};
> +
> +struct atsc_channel_info {
> +	uint8_t num_eits;
> +	uint8_t service_type;
> +	char short_name[8];
> +	uint16_t major_num;
> +	uint16_t minor_num;
> +	uint16_t tsid;
> +	uint16_t prog_num;
> +	uint16_t src_id;
> +	struct atsc_eit_info *eit;
> +	struct atsc_event_info *last_event;
> +	int event_info_index;
> +	struct atsc_event_info e[MAX_NUM_EVENTS_PER_CHANNEL];
> +	struct atsc_string_buffer title_buf;
> +	struct atsc_string_buffer msg_buf;
> +};
> +
> +struct atsc_virtual_channels_info {
> +	int num_channels;
> +	uint16_t eit_pid[MAX_NUM_EVENT_TABLES];
> +	uint16_t ett_pid[MAX_NUM_EVENT_TABLES];
> +	struct atsc_channel_info ch[MAX_NUM_CHANNELS];
> +} guide;
> +
> +struct mgt_table_name {
> +	uint16_t range;
> +	const char *string;
> +};
> +
> +struct mgt_table_name mgt_tab_name_array[] = {
> +	{0x0000, "terrestrial VCT with current_next_indictor=1"},
> +	{0x0001, "terrestrial VCT with current_next_indictor=0"},
> +	{0x0002, "cable VCT with current_next_indictor=1"},
> +	{0x0003, "cable VCT with current_next_indictor=0"},
> +	{0x0004, "channel ETT"},
> +	{0x0005, "DCCSCT"},
> +	{0x00FF, "reserved for future ATSC use"},
> +	{0x017F, "EIT"},
> +	{0x01FF, "reserved for future ATSC use"},
> +	{0x027F, "event ETT"},
> +	{0x02FF, "reserved for future ATSC use"}, /* FIXME */
> +	{0x03FF, "RRT with rating region"},
> +	{0x0FFF, "user private"},
> +	{0x13FF, "reserved for future ATSC use"},
> +	{0x14FF, "DCCT with dcc_id"},
> +	{0xFFFF, "reserved for future ATSC use"}
> +};
> +
> +const char *channel_modulation_mode[] = {
> +	"",
> +	"analog",
> +	"SCTE mode 1",
> +	"SCTE mode 2",
> +	"ATSC 8VSB",
> +	"ATSC 16VSB"
> +};
> +
> +const char *channel_service_type[] = {
> +	"",
> +	"analog TV",
> +	"ATSC digital TV",
> +	"ATSC audio",
> +	"ATSC data-only"
> +};
> +
> +void *(*table_callback[16])(struct atsc_section_psip *) =
> +{
> +	NULL, NULL, NULL, NULL, NULL, NULL, NULL,
> +	(void *(*)(struct atsc_section_psip *))atsc_mgt_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_tvct_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_cvct_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_rrt_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_eit_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_ett_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_stt_section_codec,
> +	NULL, NULL
> +};
> +
> +static void int_handler(int sig_num)
> +{
> +	if(SIGINT != sig_num) {
> +		return;
> +	}
> +	ctrl_c = 1;
> +}
> +
> +/* shamelessly stolen from dvbsnoop, but almost not modified */
> +static uint32_t get_bits(const uint8_t *buf, int startbit, int bitlen)
> +{
> +	const uint8_t *b;
> +	uint32_t mask,tmp_long;
> +	int bitHigh,i;
> +
> +	b = &buf[startbit / 8];
> +	startbit %= 8;
> +
> +	bitHigh = 8;
> +	tmp_long = b[0];
> +	for (i = 0; i < ((bitlen-1) >> 3); i++) {
> +		tmp_long <<= 8;
> +		tmp_long  |= b[i+1];
> +		bitHigh   += 8;
> +	}
> +
> +	startbit = bitHigh - startbit - bitlen;
> +	tmp_long = tmp_long >> startbit;
> +	mask     = (1ULL << bitlen) - 1;
> +	return tmp_long & mask;
> +}
> +
> +static void usage(void)
> +{
> +	fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p <period>]"
> +		" [-m <modulation>] [-t] [-h]\n", program);
> +}
> +
> +static void help(void)
> +{
> +	fprintf(stderr,
> +	"\nhelp:\n"
> +	"%s [-a <n>] -f <frequency> [-p <period>] [-m <modulation>] [-t] [-h]\n"
> +	"  -a: adapter index to use, (default 0)\n"
> +	"  -f: tuning frequency\n"
> +	"  -p: period in hours, (default 12)\n"
> +	"  -m: modulation ATSC vsb_8|vsb_16 (default vsb_8)\n"
> +	"  -t: enable ETT to receive program details, if available\n"
> +	"  -h: display this message\n", program);
> +}
> +
> +static int close_frontend(struct dvbfe_handle *fe)
> +{
> +	if(NULL == fe) {
> +		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +	}
> +
> +	dvbfe_close(fe);
> +
> +	return 0;
> +}
> +
> +static int open_frontend(struct dvbfe_handle **fe)
> +{
> +	struct dvbfe_info fe_info;
> +
> +	if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
> +		fprintf(stderr, "%s(): error calling dvbfe_open()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	dvbfe_get_info(*fe, 0, &fe_info, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
> +	if(DVBFE_TYPE_ATSC != fe_info.type) {
> +		fprintf(stderr, "%s(): only ATSC frontend supported currently\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	fe_info.feparams.frequency = frequency;
> +	fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
> +	fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
> +	fprintf(stdout, "tuning to %d Hz, please wait...\n", frequency);
> +	if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
> +		fprintf(stderr, "%s(): cannot lock to %d Hz in %d seconds\n",
> +			__FUNCTION__, frequency, TIMEOUT);
> +		return -1;
> +	}
> +	fprintf(stdout, "tuner locked.\n");
> +
> +	return 0;
> +}
> +
> +#ifdef ENABLE_RRT
> +/* this is untested as since this part of the library is broken */
> +static int parse_rrt(int dmxfd)
> +{
> +	const enum atsc_section_tag tag = stag_atsc_rating_region;
> +	struct atsc_rrt_section *rrt;
> +	struct atsc_text *region_name;
> +	struct atsc_text_string *atsc_str;
> +	int i, j, ret;
> +
> +	i = 0;
> +	fprintf(stdout, "waiting for RRT: ");
> +	fflush(stdout);
> +	while(i < RRT_TIMEOUT) {
> +		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&rrt);
> +		if(0 > ret) {
> +			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> +				__FUNCTION__);
> +			return -1;
> +		}
> +		if(0 == ret) {
> +			if(RRT_TIMEOUT > i) {
> +				fprintf(stdout, ".");
> +				fflush(stdout);
> +			} else {
> +				fprintf(stdout, "\nno RRT in %d seconds\n",
> +					RRT_TIMEOUT);
> +				return 0;
> +			}
> +			i += TIMEOUT;
> +		} else {
> +			fprintf(stdout, "\n");
> +			fflush(stdout);
> +			break;
> +		}
> +	}
> +
> +	region_name = atsc_rrt_section_rating_region_name_text(rrt);
> +	atsc_text_strings_for_each(region_name, atsc_str, i) {
> +		struct atsc_text_string_segment *seg;
> +
> +		atsc_text_string_segments_for_each(atsc_str, seg, j) {
> +			const char *c;
> +			int k;
> +			if(seg->mode < 0x3E) {
> +				fprintf(stderr, "%s(): text mode of 0x%02X "
> +					"not supported yet\n",
> +					__FUNCTION__, seg->mode);
> +				return -1;
> +			}
> +			c = (const char *)atsc_text_string_segment_bytes(seg);
> +			for(k = 0; k < seg->number_bytes; k++) {
> +				fprintf(stdout, "%c", c[k]);
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
> +static int parse_stt(int dmxfd)
> +{
> +	const enum atsc_section_tag tag = stag_atsc_system_time;
> +	const struct atsc_stt_section *stt;
> +	time_t rx_time;
> +	time_t sys_time;
> +	int ret;
> +
> +	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&stt);
> +	if(0 > ret) {
> +		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	if(0 == ret) {
> +		fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
> +		return 0;
> +	}
> +
> +	rx_time = atsctime_to_unixtime(stt->system_time);
> +	time(&sys_time);
> +	fprintf(stdout, "system time: %s", ctime(&sys_time));
> +	fprintf(stdout, "TS STT time: %s", ctime(&rx_time));
> +
> +	return 0;
> +}
> +
> +static int parse_tvct(int dmxfd)
> +{
> +	int num_sections;
> +	uint32_t section_pattern;
> +	const enum atsc_section_tag tag = stag_atsc_terrestrial_virtual_channel;
> +	struct atsc_tvct_section *tvct;
> +	struct atsc_tvct_channel *ch;
> +	struct atsc_channel_info *curr_info;
> +	int i, k, ret;
> +
> +	section_pattern = 0;
> +	num_sections = -1;
> +
> +	do {
> +		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&tvct);
> +		if(0 > ret) {
> +			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> +			__FUNCTION__);
> +			return -1;
> +		}
> +		if(0 == ret) {
> +			fprintf(stdout, "no TVCT in %d seconds\n", TIMEOUT);
> +			return 0;
> +		}
> +
> +		if(-1 == num_sections) {
> +			num_sections = 1 + tvct->head.ext_head.last_section_number;
> +			if(32 < num_sections) {
> +				fprintf(stderr, "%s(): no support yet for "
> +					"tables having more than 32 sections\n",
> +					__FUNCTION__);
> +				return -1;
> +			}
> +		} else {
> +			if(num_sections !=
> +				1 + tvct->head.ext_head.last_section_number) {
> +				fprintf(stderr,
> +					"%s(): last section number does not match\n",
> +					__FUNCTION__);
> +				return -1;
> +			}
> +		}
> +		if(section_pattern & (1 << tvct->head.ext_head.section_number)) {
> +			continue;
> +		}
> +		section_pattern |= 1 << tvct->head.ext_head.section_number;
> +
> +		if(MAX_NUM_CHANNELS < guide.num_channels +
> +			tvct->num_channels_in_section) {
> +			fprintf(stderr, "%s(): no support for more than %d "
> +				"virtual channels in a pyhsical channel\n",
> +				__FUNCTION__, MAX_NUM_CHANNELS);
> +			return -1;
> +		}
> +		curr_info = &guide.ch[guide.num_channels];
> +		guide.num_channels += tvct->num_channels_in_section;
> +
> +	atsc_tvct_section_channels_for_each(tvct, ch, i) {
> +		/* initialize the curr_info structure */
> +		/* each EIT covers 3 hours */
> +		curr_info->num_eits = (period / 3) + !!(period % 3);
> +		while (curr_info->num_eits &&
> +			(0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
> +			curr_info->num_eits -= 1;
> +		}
> +		if(curr_info->eit) {
> +			fprintf(stderr, "%s(): non-NULL pointer detected "
> +				"during initialization", __FUNCTION__);
> +			return -1;
> +		}
> +		if(NULL == (curr_info->eit = calloc(curr_info->num_eits,
> +			sizeof(struct atsc_eit_info)))) {
> +			fprintf(stderr, "%s(): error calling calloc()\n",
> +				__FUNCTION__);
> +			return -1;
> +		}
> +		if(NULL == (curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN,
> +			sizeof(char)))) {
> +			fprintf(stderr, "%s(): error calling calloc()\n",
> +				__FUNCTION__);
> +			return -1;
> +		}
> +		curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
> +		curr_info->title_buf.buf_pos = 0;
> +
> +		if(NULL == (curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN,
> +			sizeof(char)))) {
> +			fprintf(stderr, "%s(): error calling calloc()\n",
> +				__FUNCTION__);
> +			return -1;
> +		}
> +		curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
> +		curr_info->msg_buf.buf_pos = 0;
> +
> +		for(k = 0; k < 7; k++) {
> +			curr_info->short_name[k] =
> +				get_bits((const uint8_t *)ch->short_name,
> +				k * 16, 16);
> +		}
> +		curr_info->service_type = ch->service_type;
> +		curr_info->major_num = ch->major_channel_number;
> +		curr_info->minor_num = ch->minor_channel_number;
> +		curr_info->tsid = ch->channel_TSID;
> +		curr_info->prog_num = ch->program_number;
> +		curr_info->src_id = ch->source_id;
> +		curr_info++;
> +		}
> +	} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
> +
> +	return 0;
> +}
> +
> +static int match_event(struct atsc_eit_info *eit, uint16_t event_id,
> +	struct atsc_event_info **event, uint8_t *curr_index)
> +{
> +	int j, k;
> +	struct atsc_eit_section_info *section;
> +
> +	if(NULL == eit || NULL == event || NULL == curr_index) {
> +		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +		return -1;
> +	}
> +
> +	for(j = 0; j < eit->num_eit_sections; j++) {
> +		section = &eit->section[j];
> +
> +		for(k = 0; k < section->num_events; k++) {
> +			if(section->events[k] && section->events[k]->id ==
> +				event_id) {
> +				*event = section->events[k];
> +				break;
> +			}
> +		}
> +		if(*event) {
> +			*curr_index = j;
> +			break;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int parse_message(struct atsc_channel_info *channel,
> +	struct atsc_ett_section *ett, struct atsc_event_info *event)
> +{
> +	int i, j;
> +	struct atsc_text *text;
> +	struct atsc_text_string *str;
> +
> +	if(NULL == ett || NULL == event || NULL == channel) {
> +		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +		return -1;
> +	}
> +
> +	text = atsc_ett_section_extended_text_message(ett);
> +	atsc_text_strings_for_each(text, str, i) {
> +		struct atsc_text_string_segment *seg;
> +
> +		atsc_text_string_segments_for_each(str, seg, j) {
> +			event->msg_pos = channel->msg_buf.buf_pos;
> +			if(0 > atsc_text_segment_decode(seg,
> +				(uint8_t **)&channel->msg_buf.string,
> +				(size_t *)&channel->msg_buf.buf_len,
> +				(size_t *)&channel->msg_buf.buf_pos)) {
> +				fprintf(stderr, "%s(): error calling "
> +					"atsc_text_segment_decode()\n",
> +					__FUNCTION__);
> +				return -1;
> +			}
> +			event->msg_len = channel->msg_buf.buf_pos -
> +				event->msg_pos;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int parse_ett(int dmxfd, int index, uint16_t pid)
> +{
> +	uint8_t curr_index;
> +	uint32_t section_pattern;
> +	const enum atsc_section_tag tag = stag_atsc_extended_text;
> +	struct atsc_eit_info *eit;
> +	struct atsc_ett_section *ett;
> +	struct atsc_channel_info *channel;
> +	struct atsc_event_info *event;
> +	struct atsc_eit_section_info *section;
> +	uint16_t source_id, event_id;
> +	int c, ret;
> +
> +	if(0xFFFF == guide.ett_pid[index]) {
> +		return 0;
> +	}
> +
> +	for(c = 0; c < guide.num_channels; c++) {
> +		channel = &guide.ch[c];
> +		eit = &channel->eit[index];
> +
> +		section_pattern = 0;
> +		while(section_pattern !=
> +			(uint32_t)((1 << eit->num_eit_sections) - 1)) {
> +			if(ctrl_c) {
> +				return 0;
> +			}
> +			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&ett);
> +			fprintf(stdout, ".");
> +			fflush(stdout);
> +			if(0 > ret) {
> +				fprintf(stderr, "%s(): error calling "
> +					"atsc_scan_table()\n", __FUNCTION__);
> +				return -1;
> +			}
> +			if(0 == ret) {
> +				fprintf(stdout, "no ETT %d in %d seconds\n",
> +					index, TIMEOUT);
> +				return 0;
> +			}
> +
> +			source_id = ett->ETM_source_id;
> +			event_id = ett->ETM_sub_id;
> +			if(source_id != channel->src_id) {
> +				continue;
> +			}
> +
> +			event = NULL;
> +			if(match_event(eit, event_id, &event, &curr_index)) {
> +				fprintf(stderr, "%s(): error calling "
> +					"match_event()\n", __FUNCTION__);
> +				return -1;
> +			}
> +			if(NULL == event) {
> +				continue;
> +			}
> +			if(section_pattern & (1 << curr_index)) {
> +				/* the section has been filled, so skip,
> +				 * not consider version yet
> +				 */
> +				continue;
> +			}
> +			if(event->msg_len) {
> +				/* the message has been filled */
> +				continue;
> +			}
> +
> +			if(parse_message(channel, ett, event)) {
> +				fprintf(stderr, "%s(): error calling "
> +					"parse_message()\n", __FUNCTION__);
> +				return -1;
> +			}
> +			section = &eit->section[curr_index];
> +			if(++section->num_received_etms == section->num_etms) {
> +				section_pattern |= 1 << curr_index;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int parse_events(struct atsc_channel_info *curr_info,
> +	struct atsc_eit_section *eit, struct atsc_eit_section_info *section)
> +{
> +	int i, j, k;
> +	struct atsc_eit_event *e;
> +	time_t start_time, end_time;
> +
> +	if(NULL == curr_info || NULL == eit) {
> +		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +		return -1;
> +	}
> +
> +	atsc_eit_section_events_for_each(eit, e, i) {
> +		struct atsc_text *title;
> +		struct atsc_text_string *str;
> +		struct atsc_event_info *e_info =
> +			&curr_info->e[curr_info->event_info_index];
> +
> +		if(0 == i && curr_info->last_event) {
> +			if(e->event_id == curr_info->last_event->id) {
> +				section->events[i] = NULL;
> +				/* skip if it's the same event spanning
> +				 * over sections
> +				 */
> +				continue;
> +			}
> +		}
> +		curr_info->event_info_index += 1;
> +		section->events[i] = e_info;
> +		e_info->id = e->event_id;
> +		start_time = atsctime_to_unixtime(e->start_time);
> +		end_time = start_time + e->length_in_seconds;
> +		localtime_r(&start_time, &e_info->start);
> +		localtime_r(&end_time, &e_info->end);
> +		if(0 != e->ETM_location && 3 != e->ETM_location) {
> +			/* FIXME assume 1 and 2 is interchangable as of now */
> +			section->num_etms++;
> +		}
> +
> +		title = atsc_eit_event_name_title_text(e);
> +		atsc_text_strings_for_each(title, str, j) {
> +			struct atsc_text_string_segment *seg;
> +
> +			atsc_text_string_segments_for_each(str, seg, k) {
> +				e_info->title_pos = curr_info->title_buf.buf_pos;
> +				if(0 > atsc_text_segment_decode(seg,
> +					(uint8_t **)&curr_info->title_buf.string,
> +					(size_t *)&curr_info->title_buf.buf_len,
> +					(size_t *)&curr_info->title_buf.buf_pos)) {
> +					fprintf(stderr, "%s(): error calling "
> +						"atsc_text_segment_decode()\n",
> +						__FUNCTION__);
> +					return -1;
> +				}
> +				e_info->title_len = curr_info->title_buf.buf_pos -
> +					e_info->title_pos + 1;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int parse_eit(int dmxfd, int index, uint16_t pid)
> +{
> +	int num_sections;
> +	uint8_t section_num;
> +	uint8_t curr_channel_index;
> +	uint32_t section_pattern;
> +	const enum atsc_section_tag tag = stag_atsc_event_information;
> +	struct atsc_eit_section *eit;
> +	struct atsc_channel_info *curr_info;
> +	struct atsc_eit_info *eit_info;
> +	struct atsc_eit_section_info *section;
> +	uint16_t source_id;
> +	uint32_t eit_instance_pattern = 0;
> +	int i, k, ret;
> +
> +	while(eit_instance_pattern !=
> +		(uint32_t)((1 << guide.num_channels) - 1)) {
> +		source_id = 0xFFFF;
> +		section_pattern = 0;
> +		num_sections = -1;
> +
> +		do {
> +			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&eit);
> +			fprintf(stdout, ".");
> +			fflush(stdout);
> +			if(0 > ret) {
> +				fprintf(stderr, "%s(): error calling "
> +					"atsc_scan_table()\n", __FUNCTION__);
> +				return -1;
> +			}
> +			if(0 == ret) {
> +				fprintf(stdout, "no EIT %d in %d seconds\n",
> +					index, TIMEOUT);
> +				return 0;
> +			}
> +
> +			if(0xFFFF == source_id) {
> +			source_id = atsc_eit_section_source_id(eit);
> +			for(k = 0; k < guide.num_channels; k++) {
> +				if(source_id == guide.ch[k].src_id) {
> +					curr_info = &guide.ch[k];
> +					curr_channel_index = k;
> +					if(0 == index) {
> +						curr_info->last_event = NULL;
> +					}
> +					break;
> +				}
> +			}
> +			if(k == guide.num_channels) {
> +				fprintf(stderr, "%s(): cannot find source_id "
> +					"0x%04X in the EIT\n",
> +					__FUNCTION__, source_id);
> +				return -1;
> +			}
> +			} else {
> +				if(source_id !=
> +					atsc_eit_section_source_id(eit)) {
> +					continue;
> +				}
> +			}
> +			if(eit_instance_pattern & (1 << curr_channel_index)) {
> +				/* we have received this instance,
> +				 * so quit quick
> +				 */
> +				break;
> +			}
> +
> +			if(-1 == num_sections) {
> +				num_sections = 1 +
> +					eit->head.ext_head.last_section_number;
> +				if(32 < num_sections) {
> +					fprintf(stderr,
> +						"%s(): no support yet for "
> +						"tables having more than "
> +						"32 sections\n", __FUNCTION__);
> +					return -1;
> +				}
> +			} else {
> +				if(num_sections != 1 +
> +					eit->head.ext_head.last_section_number) {
> +					fprintf(stderr,
> +						"%s(): last section number "
> +						"does not match\n",
> +						__FUNCTION__);
> +					return -1;
> +				}
> +			}
> +			if(section_pattern &
> +				(1 << eit->head.ext_head.section_number)) {
> +				continue;
> +			}
> +			section_pattern |= 1 << eit->head.ext_head.section_number;
> +
> +			eit_info = &curr_info->eit[index];
> +			if(NULL == (eit_info->section =
> +				realloc(eit_info->section,
> +				(eit_info->num_eit_sections + 1) *
> +				sizeof(struct atsc_eit_section_info)))) {
> +				fprintf(stderr,
> +					"%s(): error calling realloc()\n",
> +					__FUNCTION__);
> +				return -1;
> +			}
> +			section_num = eit->head.ext_head.section_number;
> +			if(0 == eit_info->num_eit_sections) {
> +				eit_info->num_eit_sections = 1;
> +				section = eit_info->section;
> +			} else {
> +				/* have to sort it into section order
> +				 * (temporal order)
> +				 */
> +				for(i = 0; i < eit_info->num_eit_sections; i++) {
> +					if(eit_info->section[i].section_num >
> +						section_num) {
> +						break;
> +					}
> +				}
> +				memmove(&eit_info->section[i + 1],
> +					&eit_info->section[i],
> +					(eit_info->num_eit_sections - i) *
> +					sizeof(struct atsc_eit_section_info));
> +				section = &eit_info->section[i - 1];
> +				section = &eit_info->section[i];
> +				eit_info->num_eit_sections += 1;
> +			}
> +
> +			section->section_num = section_num;
> +			section->num_events = eit->num_events_in_section;
> +			section->num_etms = 0;
> +			section->num_received_etms = 0;
> +			if(NULL == (section->events = calloc(section->num_events,
> +				sizeof(struct atsc_event_info *)))) {
> +				fprintf(stderr, "%s(): error calling calloc()\n",
> +					__FUNCTION__);
> +				return -1;
> +			}
> +			if(parse_events(curr_info, eit, section)) {
> +				fprintf(stderr, "%s(): error calling "
> +					"parse_events()\n", __FUNCTION__);
> +				return -1;
> +			}
> +		} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
> +		eit_instance_pattern |= 1 << curr_channel_index;
> +	}
> +
> +	for(i = 0; i < guide.num_channels; i++) {
> +		struct atsc_channel_info *channel = &guide.ch[i];
> +		struct atsc_eit_info *ei = &channel->eit[index];
> +		struct atsc_eit_section_info *s;
> +
> +		if(0 == ei->num_eit_sections) {
> +			channel->last_event = NULL;
> +			continue;
> +		}
> +		s = &ei->section[ei->num_eit_sections - 1];
> +		/* BUG: it's incorrect when last section has no event */
> +		if(0 == s->num_events) {
> +			channel->last_event = NULL;
> +			continue;
> +		}
> +		channel->last_event = s->events[s->num_events - 1];
> +	}
> +
> +	return 0;
> +}
> +
> +static int parse_mgt(int dmxfd)
> +{
> +	const enum atsc_section_tag tag = stag_atsc_master_guide;
> +	struct atsc_mgt_section *mgt;
> +	struct atsc_mgt_table *t;
> +	int i, j, ret;
> +
> +	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&mgt);
> +	if(0 > ret) {
> +		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	if(0 == ret) {
> +		fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
> +		return 0;
> +	}
> +
> +	fprintf(stdout, "MGT table:\n");
> +	atsc_mgt_section_tables_for_each(mgt, t, i) {
> +		struct mgt_table_name table;
> +
> +	for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
> +		sizeof(struct mgt_table_name)); j++) {
> +		if(t->table_type > mgt_tab_name_array[j].range) {
> +			continue;
> +		}
> +		table = mgt_tab_name_array[j];
> +		if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
> +			mgt_tab_name_array[j].range) {
> +			j = -1;
> +		} else {
> +			j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
> +			if(0x017F == table.range) {
> +				guide.eit_pid[j] = t->table_type_PID;
> +			} else if (0x027F == table.range) {
> +				guide.ett_pid[j] = t->table_type_PID;
> +			}
> +		}
> +		break;
> +	}
> +
> +		fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X, %s", i,
> +			t->table_type, t->table_type_PID, table.string);
> +		if(-1 != j) {
> +			fprintf(stdout, " %d", j);
> +		}
> +		fprintf(stdout, "\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static int cleanup_guide(void)
> +{
> +	int i, j, k;
> +
> +	for(i = 0; i < guide.num_channels; i++) {
> +		struct atsc_channel_info *channel = &guide.ch[i];
> +
> +		if(channel->title_buf.string) {
> +			free(channel->title_buf.string);
> +		}
> +		if(channel->msg_buf.string) {
> +			free(channel->msg_buf.string);
> +		}
> +		for(j = 0; j < channel->num_eits; j++) {
> +			struct atsc_eit_info *eit = &channel->eit[j];
> +
> +			for(k = 0; k < eit->num_eit_sections; k++) {
> +				struct atsc_eit_section_info *section =
> +					&eit->section[k];
> +				if(section->num_events) {
> +					free(section->events);
> +				}
> +			}
> +			if(k) {
> +				free(eit->section);
> +			}
> +		}
> +		if(j) {
> +			free(channel->eit);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int print_events(struct atsc_channel_info *channel,
> +	struct atsc_eit_section_info *section)
> +{
> +	int m;
> +	char line[256];
> +
> +	if(NULL == section) {
> +		fprintf(stderr, "%s(): NULL pointer detected", __FUNCTION__);
> +		return -1;
> +	}
> +	for(m = 0; m < section->num_events; m++) {
> +		struct atsc_event_info *event =
> +			section->events[m];
> +
> +		if(NULL == event) {
> +			continue;
> +		}
> +		fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
> +			event->start.tm_hour, event->start.tm_min,
> +			event->end.tm_hour, event->end.tm_min);
> +		snprintf(line, event->title_len, "%s",
> +			&channel->title_buf.string[event->title_pos]);
> +		line[event->title_len] = '\0';
> +		fprintf(stdout, "%s\n", line);
> +		if(event->msg_len) {
> +			int len = event->msg_len;
> +			int pos = event->msg_pos;
> +			size_t part;
> +
> +			do {
> +				part = len > 255 ? 255 : len;
> +				snprintf(line, part + 1, "%s",
> +					&channel->msg_buf.string[pos]);
> +				line[part] = '\0';
> +				fprintf(stdout, "%s", line);
> +				len -= part;
> +				pos += part;
> +			} while(0 < len);
> +			fprintf(stdout, "\n");
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int print_guide(void)
> +{
> +	int i, j, k;
> +
> +	fprintf(stdout, "%s\n", separator);
> +	for(i = 0; i < guide.num_channels; i++) {
> +		struct atsc_channel_info *channel = &guide.ch[i];
> +
> +		fprintf(stdout, "%d.%d  %s\n", channel->major_num,
> +			channel->minor_num, channel->short_name);
> +		for(j = 0; j < channel->num_eits; j++) {
> +			struct atsc_eit_info *eit = &channel->eit[j];
> +
> +			for(k = 0; k < eit->num_eit_sections; k++) {
> +				struct atsc_eit_section_info *section =
> +					&eit->section[k];
> +				if(print_events(channel, section)) {
> +					fprintf(stderr, "%s(): error calling "
> +						"print_events()\n", __FUNCTION__);
> +					return -1;
> +				}
> +			}
> +		}
> +		fprintf(stdout, "%s\n", separator);
> +	}
> +
> +	return 0;
> +}
> +
> +static int open_demux(int *dmxfd)
> +{
> +	if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
> +		fprintf(stderr, "%s(): error calling dvbdemux_open_demux()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +static int close_demux(int dmxfd)
> +{
> +	if(dvbdemux_stop(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling dvbdemux_stop()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +/* used other utilities as template and generalized here */
> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
> +	void **table_section)
> +{
> +	uint8_t filter[18];
> +	uint8_t mask[18];
> +	unsigned char sibuf[4096];
> +	int size;
> +	int ret;
> +	struct pollfd pollfd;
> +	struct section *section;
> +	struct section_ext *section_ext;
> +	struct atsc_section_psip *psip;
> +
> +	/* create a section filter for the table */
> +	memset(filter, 0, sizeof(filter));
> +	memset(mask, 0, sizeof(mask));
> +	filter[0] = tag;
> +	mask[0] = 0xFF;
> +	if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
> +		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	/* poll for data */
> +	pollfd.fd = dmxfd;
> +	pollfd.events = POLLIN | POLLERR |POLLPRI;
> +	if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
> +		if(ctrl_c) {
> +			return 0;
> +		}
> +		fprintf(stderr, "%s(): error calling poll()\n", __FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(0 == ret) {
> +		return 0;
> +	}
> +
> +	/* read it */
> +	if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
> +		fprintf(stderr, "%s(): error calling read()\n", __FUNCTION__);
> +		return -1;
> +	}
> +
> +	/* parse section */
> +	section = section_codec(sibuf, size);
> +	if(NULL == section) {
> +		fprintf(stderr, "%s(): error calling section_codec()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	section_ext = section_ext_decode(section, 0);
> +	if(NULL == section_ext) {
> +		fprintf(stderr, "%s(): error calling section_ext_decode()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	psip = atsc_section_psip_decode(section_ext);
> +	if(NULL == psip) {
> +		fprintf(stderr,
> +			"%s(): error calling atsc_section_psip_decode()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	*table_section = table_callback[tag & 0x0F](psip);
> +	if(NULL == *table_section) {
> +		fprintf(stderr, "%s(): error decode table section\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	return 1;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	int i, dmxfd;
> +	struct dvbfe_handle *fe;
> +
> +	program = argv[0];
> +
> +	if(1 == argc) {
> +		usage();
> +		exit(-1);
> +	}
> +
> +	for( ; ; ) {
> +		char c;
> +
> +		if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
> +			break;
> +		}
> +
> +		switch(c) {
> +		case 'a':
> +			adapter = strtoll(optarg, NULL, 0);
> +			break;
> +
> +		case 'f':
> +			frequency = strtol(optarg, NULL, 0);
> +			break;
> +
> +		case 'p':
> +			period = strtol(optarg, NULL, 0);
> +			/* each table covers 3 hours */
> +			if((3 * MAX_NUM_EVENT_TABLES) < period) {
> +				period = 3 * MAX_NUM_EVENT_TABLES;
> +			}
> +			break;
> +
> +		case 'm':
> +			/* just stub, so far ATSC only has VSB_8 */
> +			modulation = optarg;
> +			break;
> +
> +		case 't':
> +			enable_ett = 1;
> +			break;
> +
> +		case 'h':
> +			help();
> +			exit(0);
> +
> +		default:
> +			usage();
> +			exit(-1);
> +		}
> +	}
> +
> +	memset(separator, '-', sizeof(separator));
> +	separator[79] = '\0';
> +	memset(&guide, 0, sizeof(struct atsc_virtual_channels_info));
> +	memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
> +	memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
> +
> +	if(open_frontend(&fe)) {
> +		fprintf(stderr, "%s(): error calling open_frontend()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(open_demux(&dmxfd)) {
> +		fprintf(stderr, "%s(): error calling open_demux()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(parse_stt(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling parse_stt()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(parse_mgt(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling parse_mgt()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(parse_tvct(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling parse_tvct()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +#ifdef ENABLE_RRT
> +	if(parse_rrt(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling parse_rrt()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +#endif
> +
> +	fprintf(stdout, "receiving EIT ");
> +	for(i = 0; i < guide.ch[0].num_eits; i++) {
> +		if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
> +			fprintf(stderr, "%s(): error calling parse_eit()\n",
> +				__FUNCTION__);
> +			return -1;
> +		}
> +	}
> +	fprintf(stdout, "\n");
> +
> +	old_handler = signal(SIGINT, int_handler);
> +	if(enable_ett) {
> +		fprintf(stdout, "receiving ETT ");
> +		for(i = 0; i < guide.ch[0].num_eits; i++) {
> +			if(0xFFFF != guide.ett_pid[i]) {
> +				if(parse_ett(dmxfd, i, guide.ett_pid[i])) {
> +					fprintf(stderr, "%s(): error calling "
> +						"parse_eit()\n", __FUNCTION__);
> +					return -1;
> +				}
> +			}
> +			if(ctrl_c) {
> +				break;
> +			}
> +		}
> +		fprintf(stdout, "\n");
> +	}
> +	signal(SIGINT, old_handler);
> +
> +	if(print_guide()) {
> +		fprintf(stderr, "%s(): error calling print_guide()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(cleanup_guide()) {
> +		fprintf(stderr, "%s(): error calling cleanup_guide()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(close_demux(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling close_demux()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(close_frontend(fe)) {
> +		fprintf(stderr, "%s(): error calling close_demux()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> diff -uprN dvb-apps/util/atsc_epg/Makefile dvb-apps_new/util/atsc_epg/Makefile
> --- dvb-apps/util/atsc_epg/Makefile	1969-12-31 18:00:00.000000000 -0600
> +++ dvb-apps_new/util/atsc_epg/Makefile	2009-06-18 20:11:58.362985962 -0500
> @@ -0,0 +1,16 @@
> +# Makefile for linuxtv.org dvb-apps/util/atsc_epg
> +
> +binaries = atsc_epg
> +
> +inst_bin = $(binaries)
> +
> +CPPFLAGS += -I../../lib -std=c99 -D_POSIX_SOURCE
> +#LDFLAGS  += -static -L../../lib/libdvbapi -L../../lib/libucsi
> +LDFLAGS  += -L../../lib/libdvbapi -L../../lib/libucsi
> +LDLIBS   += -ldvbapi -lucsi
> +
> +.PHONY: all
> +
> +all: $(binaries)
> +
> +include ../../Make.rules
> diff -uprN dvb-apps/util/atsc_epg/README dvb-apps_new/util/atsc_epg/README
> --- dvb-apps/util/atsc_epg/README	1969-12-31 18:00:00.000000000 -0600
> +++ dvb-apps_new/util/atsc_epg/README	2009-06-18 20:33:47.836924378 -0500
> @@ -0,0 +1,12 @@
> +Hi there,
> +
> +atsc_epg is a small utility for obtaining information such as programs, EPG 
> +(electronic program guide) from an ATSC channel. 
> +
> +Pulling the detailed information, i.e., option '-t', may take fairly long 
> +time, or never ending, which is a bug of the PSIP generator. Ctrl+C can be 
> +used to abort and the received parts will be printed.
> +
> +Enjoy,
> +Yufei
> +
> diff -uprN dvb-apps/util/Makefile dvb-apps_new/util/Makefile
> --- dvb-apps/util/Makefile	2009-06-18 19:43:30.034986539 -0500
> +++ dvb-apps_new/util/Makefile	2009-06-18 20:11:41.169986806 -0500
> @@ -3,6 +3,7 @@
>  .PHONY: all clean install
>  
>  all clean install:
> +	$(MAKE) -C atsc_epg $@
>  	$(MAKE) -C av7110_loadkeys $@
>  	$(MAKE) -C dib3000-watch $@
>  	$(MAKE) -C dst-utils $@
> 
> 
> On Sat, 2009-06-20 at 03:28 +0200, hermann pitton wrote: 
> > Hi,
> > 
> > Am Freitag, den 19.06.2009, 20:00 -0500 schrieb Yufei Yuan:
> > > Thanks for your time. It's my first time to do this, so I have been
> > > trying to follow literally on the wiki page to do it right. If you can
> > > elaborate a bit about what is broken? Is it the patch created
> > > incorrectly, or it is pasted incorrectly, or the style is still
> > > problematic?
> > > 
> > > I noticed that cutting and pasting from my console to the gmail
> > > compose window does not seem working alright. How do you normally do
> > > the inlining?
> > > 
> > > I have a full weekend to do this, and I do realize from the wiki page
> > > that it does not appear to be simple, :)
> > > 
> > > I now simply disable the footer, don't worry.
> > 
> > Just keep it on your decision. I'm not against to learn from the past.
> > 
> > It starts with lots of broken lines.
> > 
> > Cheers,
> > Hermann
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
       [not found]           ` <ccdf9f470906181855m2d6c471cm12afea3f228fd57c@mail.gmail.com>
@ 2009-06-20  7:30             ` Manu Abraham
  2009-06-20 13:30               ` Yufei Yuan
                                 ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Manu Abraham @ 2009-06-20  7:30 UTC (permalink / raw)
  To: Yufei Yuan; +Cc: Linux Media Mailing List

On Fri, Jun 19, 2009 at 5:55 AM, Yufei Yuan<yfyuan@gmail.com> wrote:
> Not sure how to make it look right in gmail, but the inline patch does
> not look right to my eyes. I have the patch attached behind as a
> backup.

You can attach the patch, no worries.

I have applied the patch, but the CodingStyle is not very nice, mostly
the wrapping to 80 cols is done in a bad way. It makes the code not
easy to read.

Also have made some comments inline from your patch. Please do fix the
mentioned ones against the dvb-apps head




diff -uprN dvb-apps/util/atsc_epg/atsc_epg.c
dvb-apps_new/util/atsc_epg/atsc_epg.c
--- dvb-apps/util/atsc_epg/atsc_epg.c	1969-12-31 18:00:00.000000000 -0600
+++ dvb-apps_new/util/atsc_epg/atsc_epg.c	2009-06-18 20:17:24.527925142 -0500
@@ -0,0 +1,1249 @@
+/*
+ * atsc_epg utility
+ *
+ * Copyright (C) 2009 Yufei Yuan <yfyuan@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <libdvbapi/dvbfe.h>
+#include <libdvbapi/dvbdemux.h>
+#include <libucsi/dvb/section.h>
+#include <libucsi/atsc/section.h>
+#include <libucsi/atsc/types.h>
+
+#define TIMEOUT				60
+#define RRT_TIMEOUT			60
+#define MAX_NUM_EVENT_TABLES		128
+#define TITLE_BUFFER_LEN		4096
+#define MESSAGE_BUFFER_LEN		(16 * 1024)
+#define MAX_NUM_CHANNELS		16
+#define MAX_NUM_EVENTS_PER_CHANNEL	(4 * 24 * 7)
+
+static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
+	void **table_section);
+
+static const char *program;
+static int adapter = 0;
+static int period = 12; /* hours */
+static int frequency;
+static int enable_ett = 0;
+static int ctrl_c = 0;
+static const char *modulation = NULL;
+static char separator[80];
+void (*old_handler)(int);
+
+struct atsc_string_buffer {
+	int buf_len;
+	int buf_pos;
+	char *string;
+};
+
+struct atsc_event_info {
+	uint16_t id;
+	struct tm start;
+	struct tm end;
+	int title_pos;
+	int title_len;
+	int msg_pos;
+	int msg_len;
+};
+
+struct atsc_eit_section_info {
+	uint8_t section_num;
+	uint8_t num_events;
+	uint8_t num_etms;
+	uint8_t num_received_etms;
+	struct atsc_event_info **events;
+};
+
+struct atsc_eit_info {
+	int num_eit_sections;
+	struct atsc_eit_section_info *section;
+};
+
+struct atsc_channel_info {
+	uint8_t num_eits;
+	uint8_t service_type;
+	char short_name[8];
+	uint16_t major_num;
+	uint16_t minor_num;
+	uint16_t tsid;
+	uint16_t prog_num;
+	uint16_t src_id;
+	struct atsc_eit_info *eit;
+	struct atsc_event_info *last_event;
+	int event_info_index;
+	struct atsc_event_info e[MAX_NUM_EVENTS_PER_CHANNEL];
+	struct atsc_string_buffer title_buf;
+	struct atsc_string_buffer msg_buf;
+};
+
+struct atsc_virtual_channels_info {
+	int num_channels;
+	uint16_t eit_pid[MAX_NUM_EVENT_TABLES];
+	uint16_t ett_pid[MAX_NUM_EVENT_TABLES];
+	struct atsc_channel_info ch[MAX_NUM_CHANNELS];
+} guide;
+
+struct mgt_table_name {
+	uint16_t range;
+	const char *string;
+};
+
+struct mgt_table_name mgt_tab_name_array[] = {
+	{0x0000, "terrestrial VCT with current_next_indictor=1"},
+	{0x0001, "terrestrial VCT with current_next_indictor=0"},
+	{0x0002, "cable VCT with current_next_indictor=1"},
+	{0x0003, "cable VCT with current_next_indictor=0"},
+	{0x0004, "channel ETT"},
+	{0x0005, "DCCSCT"},
+	{0x00FF, "reserved for future ATSC use"},
+	{0x017F, "EIT"},
+	{0x01FF, "reserved for future ATSC use"},
+	{0x027F, "event ETT"},
+	{0x02FF, "reserved for future ATSC use"}, /* FIXME */
+	{0x03FF, "RRT with rating region"},
+	{0x0FFF, "user private"},
+	{0x13FF, "reserved for future ATSC use"},
+	{0x14FF, "DCCT with dcc_id"},
+	{0xFFFF, "reserved for future ATSC use"}
+};
+
+const char *channel_modulation_mode[] = {
+	"",
+	"analog",
+	"SCTE mode 1",
+	"SCTE mode 2",
+	"ATSC 8VSB",
+	"ATSC 16VSB"
+};
+
+const char *channel_service_type[] = {
+	"",
+	"analog TV",
+	"ATSC digital TV",
+	"ATSC audio",
+	"ATSC data-only"
+};
+
+void *(*table_callback[16])(struct atsc_section_psip *) =
+{
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	(void *(*)(struct atsc_section_psip *))atsc_mgt_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_tvct_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_cvct_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_rrt_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_eit_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_ett_section_codec,
+	(void *(*)(struct atsc_section_psip *))atsc_stt_section_codec,
+	NULL, NULL
+};
+
+static void int_handler(int sig_num)
+{
+	if(SIGINT != sig_num) {
+		return;
+	}
+	ctrl_c = 1;
+}
+
+/* shamelessly stolen from dvbsnoop, but almost not modified */
+static uint32_t get_bits(const uint8_t *buf, int startbit, int bitlen)
+{
+	const uint8_t *b;
+	uint32_t mask,tmp_long;
+	int bitHigh,i;
+
+	b = &buf[startbit / 8];
+	startbit %= 8;
+
+	bitHigh = 8;
+	tmp_long = b[0];
+	for (i = 0; i < ((bitlen-1) >> 3); i++) {
+		tmp_long <<= 8;
+		tmp_long  |= b[i+1];
+		bitHigh   += 8;
+	}
+
+	startbit = bitHigh - startbit - bitlen;
+	tmp_long = tmp_long >> startbit;
+	mask     = (1ULL << bitlen) - 1;
+	return tmp_long & mask;
+}
+
+static void usage(void)
+{
+	fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p <period>]"
+		" [-m <modulation>] [-t] [-h]\n", program);
+}
+
+static void help(void)
+{
+	fprintf(stderr,
+	"\nhelp:\n"
+	"%s [-a <n>] -f <frequency> [-p <period>] [-m <modulation>] [-t] [-h]\n"
+	"  -a: adapter index to use, (default 0)\n"
+	"  -f: tuning frequency\n"
+	"  -p: period in hours, (default 12)\n"
+	"  -m: modulation ATSC vsb_8|vsb_16 (default vsb_8)\n"
+	"  -t: enable ETT to receive program details, if available\n"
+	"  -h: display this message\n", program);
+}
+
+static int close_frontend(struct dvbfe_handle *fe)
+{
+	if(NULL == fe) {
+		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+	}


We don't emphasise much on kernel Coding style in the application
suite, but nevertheless following a CodingStyle helps to improve the
readability of the code involved therewith.

Please do use a space after the keyword, before and after the braces.
if, for, while etc are keywords.

For a single line conditionality check, You can omit the brace,
involves lesser typing and looks lesser noise in the code.


+
+	dvbfe_close(fe);
+
+	return 0;
+}
+
+static int open_frontend(struct dvbfe_handle **fe)
+{
+	struct dvbfe_info fe_info;
+
+	if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
+		fprintf(stderr, "%s(): error calling dvbfe_open()\n",
+			__FUNCTION__);
+		return -1;
+	}
+	dvbfe_get_info(*fe, 0, &fe_info, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
+	if(DVBFE_TYPE_ATSC != fe_info.type) {
+		fprintf(stderr, "%s(): only ATSC frontend supported currently\n",
+			__FUNCTION__);
+		return -1;
+	}
+	fe_info.feparams.frequency = frequency;
+	fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
+	fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
+	fprintf(stdout, "tuning to %d Hz, please wait...\n", frequency);
+	if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
+		fprintf(stderr, "%s(): cannot lock to %d Hz in %d seconds\n",
+			__FUNCTION__, frequency, TIMEOUT);
+		return -1;
+	}
+	fprintf(stdout, "tuner locked.\n");
+
+	return 0;
+}
+
+#if ENABLE_RRT
+/* this is untested as since this part of the library is broken */
+static int parse_rrt(int dmxfd)
+{
+	const enum atsc_section_tag tag = stag_atsc_rating_region;
+	struct atsc_rrt_section *rrt;
+	struct atsc_text *region_name;
+	struct atsc_text_string *atsc_str;
+	int i, j, ret;
+
+	i = 0;
+	fprintf(stdout, "waiting for RRT: ");
+	fflush(stdout);
+	while(i < RRT_TIMEOUT) {
+		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&rrt);
+		if(0 > ret) {
+			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
+				__FUNCTION__);
+			return -1;
+		}
+		if(0 == ret) {
+			if(RRT_TIMEOUT > i) {
+				fprintf(stdout, ".");
+				fflush(stdout);
+			} else {
+				fprintf(stdout, "\nno RRT in %d seconds\n",
+					RRT_TIMEOUT);
+				return 0;
+			}
+			i += TIMEOUT;
+		} else {
+			fprintf(stdout, "\n");
+			fflush(stdout);
+			break;
+		}
+	}
+
+	region_name = atsc_rrt_section_rating_region_name_text(rrt);
+	atsc_text_strings_for_each(region_name, atsc_str, i) {
+		struct atsc_text_string_segment *seg;
+
+		atsc_text_string_segments_for_each(atsc_str, seg, j) {
+			const char *c;
+			int k;
+			if(seg->mode < 0x3E) {
+				fprintf(stderr, "%s(): text mode of 0x%02X "
+					"not supported yet\n",
+					__FUNCTION__, seg->mode);
+				return -1;
+			}
+			c = (const char *)atsc_text_string_segment_bytes(seg);
+			for(k = 0; k < seg->number_bytes; k++) {
+				fprintf(stdout, "%c", c[k]);
+			}
+		}
+	}
+
+	return 0;
+}
+#endif
+
+static int parse_stt(int dmxfd)
+{
+	const enum atsc_section_tag tag = stag_atsc_system_time;
+	const struct atsc_stt_section *stt;
+	time_t rx_time;
+	time_t sys_time;
+	int ret;
+
+	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&stt);
+	if(0 > ret) {
+		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
+			__FUNCTION__);
+		return -1;
+	}
+	if(0 == ret) {
+		fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
+		return 0;
+	}
+
+	rx_time = atsctime_to_unixtime(stt->system_time);
+	time(&sys_time);
+	fprintf(stdout, "system time: %s", ctime(&sys_time));
+	fprintf(stdout, "TS STT time: %s", ctime(&rx_time));
+
+	return 0;
+}
+
+static int parse_tvct(int dmxfd)
+{
+	int num_sections;
+	uint32_t section_pattern;
+	const enum atsc_section_tag tag = stag_atsc_terrestrial_virtual_channel;
+	struct atsc_tvct_section *tvct;
+	struct atsc_tvct_channel *ch;
+	struct atsc_channel_info *curr_info;
+	int i, k, ret;
+
+	section_pattern = 0;
+	num_sections = -1;
+
+	do {
+		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&tvct);
+		if(0 > ret) {
+			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
+			__FUNCTION__);
+			return -1;
+		}
+		if(0 == ret) {
+			fprintf(stdout, "no TVCT in %d seconds\n", TIMEOUT);
+			return 0;
+		}
+
+		if(-1 == num_sections) {
+			num_sections = 1 + tvct->head.ext_head.last_section_number;
+			if(32 < num_sections) {
+				fprintf(stderr, "%s(): no support yet for "
+					"tables having more than 32 sections\n",
+					__FUNCTION__);
+				return -1;
+			}
+		} else {
+			if(num_sections !=
+				1 + tvct->head.ext_head.last_section_number) {
+				fprintf(stderr,
+					"%s(): last section number does not match\n",
+					__FUNCTION__);
+				return -1;
+			}
+		}
+		if(section_pattern & (1 << tvct->head.ext_head.section_number)) {
+			continue;
+		}
+		section_pattern |= 1 << tvct->head.ext_head.section_number;
+
+		if(MAX_NUM_CHANNELS < guide.num_channels +
+			tvct->num_channels_in_section) {
+			fprintf(stderr, "%s(): no support for more than %d "
+				"virtual channels in a pyhsical channel\n",
+				__FUNCTION__, MAX_NUM_CHANNELS);
+			return -1;
+		}
+		curr_info = &guide.ch[guide.num_channels];
+		guide.num_channels += tvct->num_channels_in_section;
+
+	atsc_tvct_section_channels_for_each(tvct, ch, i) {
+		/* initialize the curr_info structure */
+		/* each EIT covers 3 hours */
+		curr_info->num_eits = (period / 3) + !!(period % 3);
+		while (curr_info->num_eits &&
+			(0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
+			curr_info->num_eits -= 1;
+		}
+		if(curr_info->eit) {
+			fprintf(stderr, "%s(): non-NULL pointer detected "
+				"during initialization", __FUNCTION__);
+			return -1;
+		}
+		if(NULL == (curr_info->eit = calloc(curr_info->num_eits,
+			sizeof(struct atsc_eit_info)))) {
+			fprintf(stderr, "%s(): error calling calloc()\n",
+				__FUNCTION__);
+			return -1;
+		}
+		if(NULL == (curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN,
+			sizeof(char)))) {
+			fprintf(stderr, "%s(): error calling calloc()\n",
+				__FUNCTION__);
+			return -1;
+		}
+		curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
+		curr_info->title_buf.buf_pos = 0;
+
+		if(NULL == (curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN,
+			sizeof(char)))) {
+			fprintf(stderr, "%s(): error calling calloc()\n",
+				__FUNCTION__);
+			return -1;
+		}
+		curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
+		curr_info->msg_buf.buf_pos = 0;
+
+		for(k = 0; k < 7; k++) {
+			curr_info->short_name[k] =
+				get_bits((const uint8_t *)ch->short_name,
+				k * 16, 16);
+		}
+		curr_info->service_type = ch->service_type;
+		curr_info->major_num = ch->major_channel_number;
+		curr_info->minor_num = ch->minor_channel_number;
+		curr_info->tsid = ch->channel_TSID;
+		curr_info->prog_num = ch->program_number;
+		curr_info->src_id = ch->source_id;
+		curr_info++;
+		}
+	} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
+
+	return 0;
+}
+
+static int match_event(struct atsc_eit_info *eit, uint16_t event_id,
+	struct atsc_event_info **event, uint8_t *curr_index)
+{
+	int j, k;
+	struct atsc_eit_section_info *section;
+
+	if(NULL == eit || NULL == event || NULL == curr_index) {
+		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+		return -1;
+	}
+
+	for(j = 0; j < eit->num_eit_sections; j++) {
+		section = &eit->section[j];
+
+		for(k = 0; k < section->num_events; k++) {
+			if(section->events[k] && section->events[k]->id ==
+				event_id) {
+				*event = section->events[k];
+				break;
+			}
+		}
+		if(*event) {
+			*curr_index = j;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int parse_message(struct atsc_channel_info *channel,
+	struct atsc_ett_section *ett, struct atsc_event_info *event)
+{
+	int i, j;
+	struct atsc_text *text;
+	struct atsc_text_string *str;
+
+	if(NULL == ett || NULL == event || NULL == channel) {
+		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+		return -1;
+	}
+
+	text = atsc_ett_section_extended_text_message(ett);
+	atsc_text_strings_for_each(text, str, i) {
+		struct atsc_text_string_segment *seg;
+
+		atsc_text_string_segments_for_each(str, seg, j) {
+			event->msg_pos = channel->msg_buf.buf_pos;
+			if(0 > atsc_text_segment_decode(seg,
+				(uint8_t **)&channel->msg_buf.string,
+				(size_t *)&channel->msg_buf.buf_len,
+				(size_t *)&channel->msg_buf.buf_pos)) {
+				fprintf(stderr, "%s(): error calling "
+					"atsc_text_segment_decode()\n",
+					__FUNCTION__);
+				return -1;
+			}
+			event->msg_len = 1 + channel->msg_buf.buf_pos -
+				event->msg_pos;
+		}
+	}
+
+	return 0;
+}
+
+static int parse_ett(int dmxfd, int index, uint16_t pid)
+{
+	uint8_t curr_index;
+	uint32_t section_pattern;
+	const enum atsc_section_tag tag = stag_atsc_extended_text;
+	struct atsc_eit_info *eit;
+	struct atsc_ett_section *ett;
+	struct atsc_channel_info *channel;
+	struct atsc_event_info *event;
+	struct atsc_eit_section_info *section;
+	uint16_t source_id, event_id;
+	int c, ret;
+
+	if(0xFFFF == guide.ett_pid[index]) {
+		return 0;
+	}
+
+	for(c = 0; c < guide.num_channels; c++) {
+		channel = &guide.ch[c];
+		eit = &channel->eit[index];
+
+		section_pattern = 0;
+		while(section_pattern !=
+			(uint32_t)((1 << eit->num_eit_sections) - 1)) {
+			if(ctrl_c) {
+				return 0;
+			}
+			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&ett);
+			fprintf(stdout, ".");
+			fflush(stdout);
+			if(0 > ret) {
+				fprintf(stderr, "%s(): error calling "
+					"atsc_scan_table()\n", __FUNCTION__);
+				return -1;
+			}
+			if(0 == ret) {
+				fprintf(stdout, "no ETT %d in %d seconds\n",
+					index, TIMEOUT);
+				return 0;
+			}
+
+			source_id = ett->ETM_source_id;
+			event_id = ett->ETM_sub_id;
+			if(source_id != channel->src_id) {
+				continue;
+			}
+
+			event = NULL;
+			if(match_event(eit, event_id, &event, &curr_index)) {
+				fprintf(stderr, "%s(): error calling "
+					"match_event()\n", __FUNCTION__);
+				return -1;
+			}
+			if(NULL == event) {
+				continue;
+			}
+			if(section_pattern & (1 << curr_index)) {
+				/* the section has been filled, so skip,
+				 * not consider version yet
+				 */
+				continue;
+			}
+			if(event->msg_len) {
+				/* the message has been filled */
+				continue;
+			}
+
+			if(parse_message(channel, ett, event)) {
+				fprintf(stderr, "%s(): error calling "
+					"parse_message()\n", __FUNCTION__);
+				return -1;
+			}
+			section = &eit->section[curr_index];
+			if(++section->num_received_etms == section->num_etms) {
+				section_pattern |= 1 << curr_index;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int parse_events(struct atsc_channel_info *curr_info,
+	struct atsc_eit_section *eit, struct atsc_eit_section_info *section)
+{
+	int i, j, k;
+	struct atsc_eit_event *e;
+	time_t start_time, end_time;
+
+	if(NULL == curr_info || NULL == eit) {
+		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+		return -1;
+	}
+
+	atsc_eit_section_events_for_each(eit, e, i) {
+		struct atsc_text *title;
+		struct atsc_text_string *str;
+		struct atsc_event_info *e_info =
+			&curr_info->e[curr_info->event_info_index];
+
+		if(0 == i && curr_info->last_event) {
+			if(e->event_id == curr_info->last_event->id) {
+				section->events[i] = NULL;
+				/* skip if it's the same event spanning
+				 * over sections
+				 */
+				continue;
+			}
+		}
+		curr_info->event_info_index += 1;
+		section->events[i] = e_info;
+		e_info->id = e->event_id;
+		start_time = atsctime_to_unixtime(e->start_time);
+		end_time = start_time + e->length_in_seconds;
+		localtime_r(&start_time, &e_info->start);
+		localtime_r(&end_time, &e_info->end);
+		if(0 != e->ETM_location && 3 != e->ETM_location) {
+			/* FIXME assume 1 and 2 is interchangable as of now */
+			section->num_etms++;
+		}
+
+		title = atsc_eit_event_name_title_text(e);
+		atsc_text_strings_for_each(title, str, j) {
+			struct atsc_text_string_segment *seg;
+
+			atsc_text_string_segments_for_each(str, seg, k) {
+				e_info->title_pos = curr_info->title_buf.buf_pos;
+				if(0 > atsc_text_segment_decode(seg,
+					(uint8_t **)&curr_info->title_buf.string,
+					(size_t *)&curr_info->title_buf.buf_len,
+					(size_t *)&curr_info->title_buf.buf_pos)) {
+					fprintf(stderr, "%s(): error calling "
+						"atsc_text_segment_decode()\n",
+						__FUNCTION__);



Please don't wrap lines like this. It makes the code readability very
bad. There is not much of a restriction to limit the no. of cols to
80, though at some points of times that helps in some ways.

Here but it really shows out that the wrapping to 80 cols makes it
really bad. A very good example.


+					return -1;
+				}
+				e_info->title_len = curr_info->title_buf.buf_pos -
+					e_info->title_pos + 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int parse_eit(int dmxfd, int index, uint16_t pid)
+{
+	int num_sections;
+	uint8_t section_num;
+	uint8_t curr_channel_index;
+	uint32_t section_pattern;
+	const enum atsc_section_tag tag = stag_atsc_event_information;
+	struct atsc_eit_section *eit;
+	struct atsc_channel_info *curr_info;
+	struct atsc_eit_info *eit_info;
+	struct atsc_eit_section_info *section;
+	uint16_t source_id;
+	uint32_t eit_instance_pattern = 0;
+	int i, k, ret;
+
+	while(eit_instance_pattern !=
+		(uint32_t)((1 << guide.num_channels) - 1)) {
+		source_id = 0xFFFF;
+		section_pattern = 0;
+		num_sections = -1;
+
+		do {
+			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&eit);
+			fprintf(stdout, ".");
+			fflush(stdout);
+			if(0 > ret) {
+				fprintf(stderr, "%s(): error calling "
+					"atsc_scan_table()\n", __FUNCTION__);
+				return -1;
+			}
+			if(0 == ret) {
+				fprintf(stdout, "no EIT %d in %d seconds\n",
+					index, TIMEOUT);
+				return 0;
+			}
+
+			if(0xFFFF == source_id) {
+			source_id = atsc_eit_section_source_id(eit);
+			for(k = 0; k < guide.num_channels; k++) {
+				if(source_id == guide.ch[k].src_id) {
+					curr_info = &guide.ch[k];
+					curr_channel_index = k;
+					if(0 == index) {
+						curr_info->last_event = NULL;
+					}
+					break;
+				}
+			}
+			if(k == guide.num_channels) {
+				fprintf(stderr, "%s(): cannot find source_id "
+					"0x%04X in the EIT\n",
+					__FUNCTION__, source_id);
+				return -1;
+			}
+			} else {
+				if(source_id !=
+					atsc_eit_section_source_id(eit)) {
+					continue;
+				}
+			}
+			if(eit_instance_pattern & (1 << curr_channel_index)) {
+				/* we have received this instance,
+				 * so quit quick
+				 */
+				break;
+			}
+
+			if(-1 == num_sections) {
+				num_sections = 1 +
+					eit->head.ext_head.last_section_number;
+				if(32 < num_sections) {
+					fprintf(stderr,
+						"%s(): no support yet for "
+						"tables having more than "
+						"32 sections\n", __FUNCTION__);
+					return -1;
+				}
+			} else {
+				if(num_sections != 1 +
+					eit->head.ext_head.last_section_number) {
+					fprintf(stderr,
+						"%s(): last section number "
+						"does not match\n",
+						__FUNCTION__);
+					return -1;
+				}
+			}
+			if(section_pattern &
+				(1 << eit->head.ext_head.section_number)) {
+				continue;
+			}
+			section_pattern |= 1 << eit->head.ext_head.section_number;
+
+			eit_info = &curr_info->eit[index];
+			if(NULL == (eit_info->section =
+				realloc(eit_info->section,
+				(eit_info->num_eit_sections + 1) *
+				sizeof(struct atsc_eit_section_info)))) {
+				fprintf(stderr,
+					"%s(): error calling realloc()\n",
+					__FUNCTION__);
+				return -1;
+			}
+			section_num = eit->head.ext_head.section_number;
+			if(0 == eit_info->num_eit_sections) {
+				eit_info->num_eit_sections = 1;
+				section = eit_info->section;
+			} else {
+				/* have to sort it into section order
+				 * (temporal order)
+				 */
+				for(i = 0; i < eit_info->num_eit_sections; i++) {
+					if(eit_info->section[i].section_num >
+						section_num) {
+						break;
+					}
+				}
+				memmove(&eit_info->section[i + 1],
+					&eit_info->section[i],
+					(eit_info->num_eit_sections - i) *
+					sizeof(struct atsc_eit_section_info));
+				section = &eit_info->section[i - 1];
+				section = &eit_info->section[i];
+				eit_info->num_eit_sections += 1;
+			}
+
+			section->section_num = section_num;
+			section->num_events = eit->num_events_in_section;
+			section->num_etms = 0;
+			section->num_received_etms = 0;
+			if(NULL == (section->events = calloc(section->num_events,
+				sizeof(struct atsc_event_info *)))) {
+				fprintf(stderr, "%s(): error calling calloc()\n",
+					__FUNCTION__);
+				return -1;
+			}
+			if(parse_events(curr_info, eit, section)) {
+				fprintf(stderr, "%s(): error calling "
+					"parse_events()\n", __FUNCTION__);
+				return -1;
+			}
+		} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
+		eit_instance_pattern |= 1 << curr_channel_index;
+	}
+
+	for(i = 0; i < guide.num_channels; i++) {
+		struct atsc_channel_info *channel = &guide.ch[i];
+		struct atsc_eit_info *ei = &channel->eit[index];
+		struct atsc_eit_section_info *s;
+
+		if(0 == ei->num_eit_sections) {
+			channel->last_event = NULL;
+			continue;
+		}
+		s = &ei->section[ei->num_eit_sections - 1];
+		/* BUG: it's incorrect when last section has no event */
+		if(0 == s->num_events) {
+			channel->last_event = NULL;
+			continue;
+		}
+		channel->last_event = s->events[s->num_events - 1];
+	}
+
+	return 0;
+}
+
+static int parse_mgt(int dmxfd)
+{
+	const enum atsc_section_tag tag = stag_atsc_master_guide;
+	struct atsc_mgt_section *mgt;
+	struct atsc_mgt_table *t;
+	int i, j, ret;
+
+	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&mgt);
+	if(0 > ret) {
+		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
+			__FUNCTION__);
+		return -1;
+	}
+	if(0 == ret) {
+		fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
+		return 0;
+	}
+
+	fprintf(stdout, "MGT table:\n");
+	atsc_mgt_section_tables_for_each(mgt, t, i) {
+		struct mgt_table_name table;
+
+	for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
+		sizeof(struct mgt_table_name)); j++) {
+		if(t->table_type > mgt_tab_name_array[j].range) {
+			continue;
+		}
+		table = mgt_tab_name_array[j];
+		if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
+			mgt_tab_name_array[j].range) {
+			j = -1;
+		} else {
+			j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
+			if(0x017F == table.range) {
+				guide.eit_pid[j] = t->table_type_PID;
+			} else if (0x027F == table.range) {
+				guide.ett_pid[j] = t->table_type_PID;
+			}
+		}
+		break;
+	}
+
+		fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X, %s", i,
+		    t->table_type, t->table_type_PID, table.string);
+		if(-1 != j) {
+		    fprintf(stdout, " %d", j);
+		}
+		fprintf(stdout, "\n");
+	}
+
+	return 0;
+}
+
+static int cleanup_guide(void)
+{
+	int i, j, k;
+
+	for(i = 0; i < guide.num_channels; i++) {
+		struct atsc_channel_info *channel = &guide.ch[i];
+
+		if(channel->title_buf.string) {
+			free(channel->title_buf.string);
+		}
+		if(channel->msg_buf.string) {
+			free(channel->msg_buf.string);
+		}
+		for(j = 0; j < channel->num_eits; j++) {
+			struct atsc_eit_info *eit = &channel->eit[j];
+
+			for(k = 0; k < eit->num_eit_sections; k++) {
+				struct atsc_eit_section_info *section =
+					&eit->section[k];
+				if(section->num_events) {
+					free(section->events);
+				}
+			}
+			if(k) {
+				free(eit->section);
+			}
+		}
+		if(j) {
+			free(channel->eit);
+		}
+	}
+
+	return 0;
+}
+
+static int print_events(struct atsc_channel_info *channel,
+	struct atsc_eit_section_info *section)
+{
+	int m;
+	char line[256];
+
+	if(NULL == section) {
+		fprintf(stderr, "%s(): NULL pointer detected", __FUNCTION__);
+		return -1;
+	}
+	for(m = 0; m < section->num_events; m++) {
+		struct atsc_event_info *event =
+			section->events[m];
+
+		if(NULL == event) {
+			continue;
+		}
+		fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
+			event->start.tm_hour, event->start.tm_min,
+			event->end.tm_hour, event->end.tm_min);
+		snprintf(line, event->title_len, "%s",
+			&channel->title_buf.string[event->title_pos]);
+		line[event->title_len] = '\0';
+		fprintf(stdout, "%s\n", line);
+		if(event->msg_len) {
+			int len = event->msg_len;
+			int pos = event->msg_pos;
+			size_t part;
+
+			do {
+				part = len > 255 ? 255 : len;
+				snprintf(line, part, "%s",
+					&channel->msg_buf.string[pos]);
+				line[part] = '\0';
+				fprintf(stdout, "%s", line);
+				len -= part;
+				pos += part;
+			} while(0 < len);
+			fprintf(stdout, "\n");
+		}
+	}
+	return 0;
+}
+
+static int print_guide(void)
+{
+	int i, j, k;
+
+	fprintf(stdout, "%s\n", separator);
+	for(i = 0; i < guide.num_channels; i++) {
+		struct atsc_channel_info *channel = &guide.ch[i];
+
+		fprintf(stdout, "%d.%d  %s\n", channel->major_num,
+			channel->minor_num, channel->short_name);
+		for(j = 0; j < channel->num_eits; j++) {
+			struct atsc_eit_info *eit = &channel->eit[j];
+
+			for(k = 0; k < eit->num_eit_sections; k++) {
+				struct atsc_eit_section_info *section =
+					&eit->section[k];
+				if(print_events(channel, section)) {
+					fprintf(stderr, "%s(): error calling "
+						"print_events()\n", __FUNCTION__);
+					return -1;
+				}
+			}
+		}
+		fprintf(stdout, "%s\n", separator);
+	}
+
+	return 0;
+}
+
+static int open_demux(int *dmxfd)
+{
+	if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
+		fprintf(stderr, "%s(): error calling dvbdemux_open_demux()\n",
+			__FUNCTION__);
+		return -1;
+	}
+	return 0;
+}
+
+static int close_demux(int dmxfd)
+{
+	if(dvbdemux_stop(dmxfd)) {
+		fprintf(stderr, "%s(): error calling dvbdemux_stop()\n",
+			__FUNCTION__);
+		return -1;
+	}
+	return 0;
+}
+
+/* used other utilities as template and generalized here */
+static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
+	void **table_section)
+{
+	uint8_t filter[18];
+	uint8_t mask[18];
+	unsigned char sibuf[4096];
+	int size;
+	int ret;
+	struct pollfd pollfd;
+	struct section *section;
+	struct section_ext *section_ext;
+	struct atsc_section_psip *psip;
+
+	/* create a section filter for the table */
+	memset(filter, 0, sizeof(filter));
+	memset(mask, 0, sizeof(mask));
+	filter[0] = tag;
+	mask[0] = 0xFF;
+	if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
+		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	/* poll for data */
+	pollfd.fd = dmxfd;
+	pollfd.events = POLLIN | POLLERR |POLLPRI;
+	if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
+		if(ctrl_c) {
+			return 0;
+		}
+		fprintf(stderr, "%s(): error calling poll()\n", __FUNCTION__);
+		return -1;
+	}
+
+	if(0 == ret) {
+		return 0;
+	}
+
+	/* read it */
+	if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
+		fprintf(stderr, "%s(): error calling read()\n", __FUNCTION__);
+		return -1;
+	}
+
+	/* parse section */
+	section = section_codec(sibuf, size);
+	if(NULL == section) {
+		fprintf(stderr, "%s(): error calling section_codec()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	section_ext = section_ext_decode(section, 0);
+	if(NULL == section_ext) {
+		fprintf(stderr, "%s(): error calling section_ext_decode()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	psip = atsc_section_psip_decode(section_ext);
+	if(NULL == psip) {
+		fprintf(stderr,
+			"%s(): error calling atsc_section_psip_decode()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	*table_section = table_callback[tag & 0x0F](psip);
+	if(NULL == *table_section) {
+		fprintf(stderr, "%s(): error decode table section\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	int i, dmxfd;
+	struct dvbfe_handle *fe;
+
+	program = argv[0];
+
+	if(1 == argc) {
+		usage();
+		exit(-1);
+	}
+
+	for( ; ; ) {
+		char c;
+
+		if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
+			break;
+		}
+
+		switch(c) {
+		case 'a':
+			adapter = strtoll(optarg, NULL, 0);
+			break;
+
+		case 'f':
+			frequency = strtol(optarg, NULL, 0);
+			break;
+
+		case 'p':
+			period = strtol(optarg, NULL, 0);
+			/* each table covers 3 hours */
+			if((3 * MAX_NUM_EVENT_TABLES) < period) {
+				period = 3 * MAX_NUM_EVENT_TABLES;
+			}
+			break;
+
+		case 'm':
+			/* just stub, so far ATSC only has VSB_8 */
+			modulation = optarg;
+			break;
+
+		case 't':
+			enable_ett = 1;
+			break;
+
+		case 'h':
+			help();
+			exit(0);
+
+		default:
+			usage();
+			exit(-1);
+		}
+	}
+
+	memset(separator, '-', sizeof(separator));
+	separator[79] = '\0';
+	memset(&guide, 0, sizeof(struct atsc_virtual_channels_info));
+	memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
+	memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
+
+	if(open_frontend(&fe)) {
+		fprintf(stderr, "%s(): error calling open_frontend()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(open_demux(&dmxfd)) {
+		fprintf(stderr, "%s(): error calling open_demux()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(parse_stt(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_stt()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(parse_mgt(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_mgt()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(parse_tvct(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_tvct()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+#ifdef ENABLE_RRT
+	if(parse_rrt(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_rrt()\n",
+			__FUNCTION__);
+		return -1;
+	}
+#endif
+
+	fprintf(stdout, "receiving EIT ");
+	for(i = 0; i < guide.ch[0].num_eits; i++) {
+		if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
+			fprintf(stderr, "%s(): error calling parse_eit()\n",
+				__FUNCTION__);
+			return -1;
+		}
+	}
+	fprintf(stdout, "\n");
+
+	old_handler = signal(SIGINT, int_handler);
+	if(enable_ett) {
+		fprintf(stdout, "receiving ETT ");
+		for(i = 0; i < guide.ch[0].num_eits; i++) {
+			if(0xFFFF != guide.ett_pid[i]) {
+				if(parse_ett(dmxfd, i, guide.ett_pid[i])) {
+					fprintf(stderr, "%s(): error calling "
+						"parse_eit()\n", __FUNCTION__);
+					return -1;
+				}
+			}
+			if(ctrl_c) {
+				break;
+			}
+		}
+		fprintf(stdout, "\n");
+	}
+	signal(SIGINT, old_handler);
+
+	if(print_guide()) {
+		fprintf(stderr, "%s(): error calling print_guide()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(cleanup_guide()) {
+		fprintf(stderr, "%s(): error calling cleanup_guide()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(close_demux(dmxfd)) {
+		fprintf(stderr, "%s(): error calling close_demux()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	if(close_frontend(fe)) {
+		fprintf(stderr, "%s(): error calling close_demux()\n",
+			__FUNCTION__);
+		return -1;
+	}
+
+	return 0;
+}
diff -uprN dvb-apps/util/atsc_epg/Makefile dvb-apps_new/util/atsc_epg/Makefile
--- dvb-apps/util/atsc_epg/Makefile	1969-12-31 18:00:00.000000000 -0600
+++ dvb-apps_new/util/atsc_epg/Makefile	2009-06-18 20:11:58.362985962 -0500
@@ -0,0 +1,16 @@
+# Makefile for linuxtv.org dvb-apps/util/atsc_epg
+
+binaries = atsc_epg
+
+inst_bin = $(binaries)
+
+CPPFLAGS += -I../../lib -std=c99 -D_POSIX_SOURCE
+#LDFLAGS  += -static -L../../lib/libdvbapi -L../../lib/libucsi
+LDFLAGS  += -L../../lib/libdvbapi -L../../lib/libucsi
+LDLIBS   += -ldvbapi -lucsi
+
+.PHONY: all
+
+all: $(binaries)
+
+include ../../Make.rules
diff -uprN dvb-apps/util/atsc_epg/README dvb-apps_new/util/atsc_epg/README
--- dvb-apps/util/atsc_epg/README	1969-12-31 18:00:00.000000000 -0600
+++ dvb-apps_new/util/atsc_epg/README	2009-06-18 20:33:47.836924378 -0500
@@ -0,0 +1,12 @@
+Hi there,
+
+atsc_epg is a small utility for obtaining information such as programs, EPG
+(electronic program guide) from an ATSC channel.
+
+Pulling the detailed information, i.e., option '-t', may take fairly long
+time, or never ending, which is a bug of the PSIP generator. Ctrl+C can be
+used to abort and the received parts will be printed.
+
+Enjoy,
+Yufei
+
diff -uprN dvb-apps/util/Makefile dvb-apps_new/util/Makefile
--- dvb-apps/util/Makefile	2009-06-18 19:43:30.034986539 -0500
+++ dvb-apps_new/util/Makefile	2009-06-18 20:11:41.169986806 -0500
@@ -3,6 +3,7 @@
 .PHONY: all clean install

 all clean install:
+	$(MAKE) -C atsc_epg $@
 	$(MAKE) -C av7110_loadkeys $@
 	$(MAKE) -C dib3000-watch $@
 	$(MAKE) -C dst-utils $@


Regards,
Manu

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-20  7:30             ` Manu Abraham
@ 2009-06-20 13:30               ` Yufei Yuan
  2009-06-20 17:15               ` [Patch] dvb-apps: code cleanup and bug fix Yufei Yuan
  2009-06-22 23:43               ` [Patch] New utility program atsc_epg added to dvb-apps utility suite Yufei Yuan
  2 siblings, 0 replies; 22+ messages in thread
From: Yufei Yuan @ 2009-06-20 13:30 UTC (permalink / raw)
  To: Manu Abraham; +Cc: Linux Media Mailing List

Thanks for the feedback. Will fix the coding style, and send in a new one 
against the tip.

Regards,

On Sat, 2009-06-20 at 11:30 +0400, Manu Abraham wrote:
> On Fri, Jun 19, 2009 at 5:55 AM, Yufei Yuan<yfyuan@gmail.com> wrote:
> > Not sure how to make it look right in gmail, but the inline patch does
> > not look right to my eyes. I have the patch attached behind as a
> > backup.
> 
> You can attach the patch, no worries.
> 
> I have applied the patch, but the CodingStyle is not very nice, mostly
> the wrapping to 80 cols is done in a bad way. It makes the code not
> easy to read.
> 
> Also have made some comments inline from your patch. Please do fix the
> mentioned ones against the dvb-apps head
> 
> 
> 
> 
> diff -uprN dvb-apps/util/atsc_epg/atsc_epg.c
> dvb-apps_new/util/atsc_epg/atsc_epg.c
> --- dvb-apps/util/atsc_epg/atsc_epg.c	1969-12-31 18:00:00.000000000 -0600
> +++ dvb-apps_new/util/atsc_epg/atsc_epg.c	2009-06-18 20:17:24.527925142 -0500
> @@ -0,0 +1,1249 @@
> +/*
> + * atsc_epg utility
> + *
> + * Copyright (C) 2009 Yufei Yuan <yfyuan@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <time.h>
> +#include <signal.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <sys/ioctl.h>
> +#include <sys/poll.h>
> +#include <errno.h>
> +#include <getopt.h>
> +#include <stdarg.h>
> +#include <libdvbapi/dvbfe.h>
> +#include <libdvbapi/dvbdemux.h>
> +#include <libucsi/dvb/section.h>
> +#include <libucsi/atsc/section.h>
> +#include <libucsi/atsc/types.h>
> +
> +#define TIMEOUT				60
> +#define RRT_TIMEOUT			60
> +#define MAX_NUM_EVENT_TABLES		128
> +#define TITLE_BUFFER_LEN		4096
> +#define MESSAGE_BUFFER_LEN		(16 * 1024)
> +#define MAX_NUM_CHANNELS		16
> +#define MAX_NUM_EVENTS_PER_CHANNEL	(4 * 24 * 7)
> +
> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
> +	void **table_section);
> +
> +static const char *program;
> +static int adapter = 0;
> +static int period = 12; /* hours */
> +static int frequency;
> +static int enable_ett = 0;
> +static int ctrl_c = 0;
> +static const char *modulation = NULL;
> +static char separator[80];
> +void (*old_handler)(int);
> +
> +struct atsc_string_buffer {
> +	int buf_len;
> +	int buf_pos;
> +	char *string;
> +};
> +
> +struct atsc_event_info {
> +	uint16_t id;
> +	struct tm start;
> +	struct tm end;
> +	int title_pos;
> +	int title_len;
> +	int msg_pos;
> +	int msg_len;
> +};
> +
> +struct atsc_eit_section_info {
> +	uint8_t section_num;
> +	uint8_t num_events;
> +	uint8_t num_etms;
> +	uint8_t num_received_etms;
> +	struct atsc_event_info **events;
> +};
> +
> +struct atsc_eit_info {
> +	int num_eit_sections;
> +	struct atsc_eit_section_info *section;
> +};
> +
> +struct atsc_channel_info {
> +	uint8_t num_eits;
> +	uint8_t service_type;
> +	char short_name[8];
> +	uint16_t major_num;
> +	uint16_t minor_num;
> +	uint16_t tsid;
> +	uint16_t prog_num;
> +	uint16_t src_id;
> +	struct atsc_eit_info *eit;
> +	struct atsc_event_info *last_event;
> +	int event_info_index;
> +	struct atsc_event_info e[MAX_NUM_EVENTS_PER_CHANNEL];
> +	struct atsc_string_buffer title_buf;
> +	struct atsc_string_buffer msg_buf;
> +};
> +
> +struct atsc_virtual_channels_info {
> +	int num_channels;
> +	uint16_t eit_pid[MAX_NUM_EVENT_TABLES];
> +	uint16_t ett_pid[MAX_NUM_EVENT_TABLES];
> +	struct atsc_channel_info ch[MAX_NUM_CHANNELS];
> +} guide;
> +
> +struct mgt_table_name {
> +	uint16_t range;
> +	const char *string;
> +};
> +
> +struct mgt_table_name mgt_tab_name_array[] = {
> +	{0x0000, "terrestrial VCT with current_next_indictor=1"},
> +	{0x0001, "terrestrial VCT with current_next_indictor=0"},
> +	{0x0002, "cable VCT with current_next_indictor=1"},
> +	{0x0003, "cable VCT with current_next_indictor=0"},
> +	{0x0004, "channel ETT"},
> +	{0x0005, "DCCSCT"},
> +	{0x00FF, "reserved for future ATSC use"},
> +	{0x017F, "EIT"},
> +	{0x01FF, "reserved for future ATSC use"},
> +	{0x027F, "event ETT"},
> +	{0x02FF, "reserved for future ATSC use"}, /* FIXME */
> +	{0x03FF, "RRT with rating region"},
> +	{0x0FFF, "user private"},
> +	{0x13FF, "reserved for future ATSC use"},
> +	{0x14FF, "DCCT with dcc_id"},
> +	{0xFFFF, "reserved for future ATSC use"}
> +};
> +
> +const char *channel_modulation_mode[] = {
> +	"",
> +	"analog",
> +	"SCTE mode 1",
> +	"SCTE mode 2",
> +	"ATSC 8VSB",
> +	"ATSC 16VSB"
> +};
> +
> +const char *channel_service_type[] = {
> +	"",
> +	"analog TV",
> +	"ATSC digital TV",
> +	"ATSC audio",
> +	"ATSC data-only"
> +};
> +
> +void *(*table_callback[16])(struct atsc_section_psip *) =
> +{
> +	NULL, NULL, NULL, NULL, NULL, NULL, NULL,
> +	(void *(*)(struct atsc_section_psip *))atsc_mgt_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_tvct_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_cvct_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_rrt_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_eit_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_ett_section_codec,
> +	(void *(*)(struct atsc_section_psip *))atsc_stt_section_codec,
> +	NULL, NULL
> +};
> +
> +static void int_handler(int sig_num)
> +{
> +	if(SIGINT != sig_num) {
> +		return;
> +	}
> +	ctrl_c = 1;
> +}
> +
> +/* shamelessly stolen from dvbsnoop, but almost not modified */
> +static uint32_t get_bits(const uint8_t *buf, int startbit, int bitlen)
> +{
> +	const uint8_t *b;
> +	uint32_t mask,tmp_long;
> +	int bitHigh,i;
> +
> +	b = &buf[startbit / 8];
> +	startbit %= 8;
> +
> +	bitHigh = 8;
> +	tmp_long = b[0];
> +	for (i = 0; i < ((bitlen-1) >> 3); i++) {
> +		tmp_long <<= 8;
> +		tmp_long  |= b[i+1];
> +		bitHigh   += 8;
> +	}
> +
> +	startbit = bitHigh - startbit - bitlen;
> +	tmp_long = tmp_long >> startbit;
> +	mask     = (1ULL << bitlen) - 1;
> +	return tmp_long & mask;
> +}
> +
> +static void usage(void)
> +{
> +	fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p <period>]"
> +		" [-m <modulation>] [-t] [-h]\n", program);
> +}
> +
> +static void help(void)
> +{
> +	fprintf(stderr,
> +	"\nhelp:\n"
> +	"%s [-a <n>] -f <frequency> [-p <period>] [-m <modulation>] [-t] [-h]\n"
> +	"  -a: adapter index to use, (default 0)\n"
> +	"  -f: tuning frequency\n"
> +	"  -p: period in hours, (default 12)\n"
> +	"  -m: modulation ATSC vsb_8|vsb_16 (default vsb_8)\n"
> +	"  -t: enable ETT to receive program details, if available\n"
> +	"  -h: display this message\n", program);
> +}
> +
> +static int close_frontend(struct dvbfe_handle *fe)
> +{
> +	if(NULL == fe) {
> +		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +	}
> 
> 
> We don't emphasise much on kernel Coding style in the application
> suite, but nevertheless following a CodingStyle helps to improve the
> readability of the code involved therewith.
> 
> Please do use a space after the keyword, before and after the braces.
> if, for, while etc are keywords.
> 
> For a single line conditionality check, You can omit the brace,
> involves lesser typing and looks lesser noise in the code.
> 
> 
> +
> +	dvbfe_close(fe);
> +
> +	return 0;
> +}
> +
> +static int open_frontend(struct dvbfe_handle **fe)
> +{
> +	struct dvbfe_info fe_info;
> +
> +	if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
> +		fprintf(stderr, "%s(): error calling dvbfe_open()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	dvbfe_get_info(*fe, 0, &fe_info, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
> +	if(DVBFE_TYPE_ATSC != fe_info.type) {
> +		fprintf(stderr, "%s(): only ATSC frontend supported currently\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	fe_info.feparams.frequency = frequency;
> +	fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
> +	fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
> +	fprintf(stdout, "tuning to %d Hz, please wait...\n", frequency);
> +	if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
> +		fprintf(stderr, "%s(): cannot lock to %d Hz in %d seconds\n",
> +			__FUNCTION__, frequency, TIMEOUT);
> +		return -1;
> +	}
> +	fprintf(stdout, "tuner locked.\n");
> +
> +	return 0;
> +}
> +
> +#if ENABLE_RRT
> +/* this is untested as since this part of the library is broken */
> +static int parse_rrt(int dmxfd)
> +{
> +	const enum atsc_section_tag tag = stag_atsc_rating_region;
> +	struct atsc_rrt_section *rrt;
> +	struct atsc_text *region_name;
> +	struct atsc_text_string *atsc_str;
> +	int i, j, ret;
> +
> +	i = 0;
> +	fprintf(stdout, "waiting for RRT: ");
> +	fflush(stdout);
> +	while(i < RRT_TIMEOUT) {
> +		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&rrt);
> +		if(0 > ret) {
> +			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> +				__FUNCTION__);
> +			return -1;
> +		}
> +		if(0 == ret) {
> +			if(RRT_TIMEOUT > i) {
> +				fprintf(stdout, ".");
> +				fflush(stdout);
> +			} else {
> +				fprintf(stdout, "\nno RRT in %d seconds\n",
> +					RRT_TIMEOUT);
> +				return 0;
> +			}
> +			i += TIMEOUT;
> +		} else {
> +			fprintf(stdout, "\n");
> +			fflush(stdout);
> +			break;
> +		}
> +	}
> +
> +	region_name = atsc_rrt_section_rating_region_name_text(rrt);
> +	atsc_text_strings_for_each(region_name, atsc_str, i) {
> +		struct atsc_text_string_segment *seg;
> +
> +		atsc_text_string_segments_for_each(atsc_str, seg, j) {
> +			const char *c;
> +			int k;
> +			if(seg->mode < 0x3E) {
> +				fprintf(stderr, "%s(): text mode of 0x%02X "
> +					"not supported yet\n",
> +					__FUNCTION__, seg->mode);
> +				return -1;
> +			}
> +			c = (const char *)atsc_text_string_segment_bytes(seg);
> +			for(k = 0; k < seg->number_bytes; k++) {
> +				fprintf(stdout, "%c", c[k]);
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
> +static int parse_stt(int dmxfd)
> +{
> +	const enum atsc_section_tag tag = stag_atsc_system_time;
> +	const struct atsc_stt_section *stt;
> +	time_t rx_time;
> +	time_t sys_time;
> +	int ret;
> +
> +	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&stt);
> +	if(0 > ret) {
> +		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	if(0 == ret) {
> +		fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
> +		return 0;
> +	}
> +
> +	rx_time = atsctime_to_unixtime(stt->system_time);
> +	time(&sys_time);
> +	fprintf(stdout, "system time: %s", ctime(&sys_time));
> +	fprintf(stdout, "TS STT time: %s", ctime(&rx_time));
> +
> +	return 0;
> +}
> +
> +static int parse_tvct(int dmxfd)
> +{
> +	int num_sections;
> +	uint32_t section_pattern;
> +	const enum atsc_section_tag tag = stag_atsc_terrestrial_virtual_channel;
> +	struct atsc_tvct_section *tvct;
> +	struct atsc_tvct_channel *ch;
> +	struct atsc_channel_info *curr_info;
> +	int i, k, ret;
> +
> +	section_pattern = 0;
> +	num_sections = -1;
> +
> +	do {
> +		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&tvct);
> +		if(0 > ret) {
> +			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> +			__FUNCTION__);
> +			return -1;
> +		}
> +		if(0 == ret) {
> +			fprintf(stdout, "no TVCT in %d seconds\n", TIMEOUT);
> +			return 0;
> +		}
> +
> +		if(-1 == num_sections) {
> +			num_sections = 1 + tvct->head.ext_head.last_section_number;
> +			if(32 < num_sections) {
> +				fprintf(stderr, "%s(): no support yet for "
> +					"tables having more than 32 sections\n",
> +					__FUNCTION__);
> +				return -1;
> +			}
> +		} else {
> +			if(num_sections !=
> +				1 + tvct->head.ext_head.last_section_number) {
> +				fprintf(stderr,
> +					"%s(): last section number does not match\n",
> +					__FUNCTION__);
> +				return -1;
> +			}
> +		}
> +		if(section_pattern & (1 << tvct->head.ext_head.section_number)) {
> +			continue;
> +		}
> +		section_pattern |= 1 << tvct->head.ext_head.section_number;
> +
> +		if(MAX_NUM_CHANNELS < guide.num_channels +
> +			tvct->num_channels_in_section) {
> +			fprintf(stderr, "%s(): no support for more than %d "
> +				"virtual channels in a pyhsical channel\n",
> +				__FUNCTION__, MAX_NUM_CHANNELS);
> +			return -1;
> +		}
> +		curr_info = &guide.ch[guide.num_channels];
> +		guide.num_channels += tvct->num_channels_in_section;
> +
> +	atsc_tvct_section_channels_for_each(tvct, ch, i) {
> +		/* initialize the curr_info structure */
> +		/* each EIT covers 3 hours */
> +		curr_info->num_eits = (period / 3) + !!(period % 3);
> +		while (curr_info->num_eits &&
> +			(0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
> +			curr_info->num_eits -= 1;
> +		}
> +		if(curr_info->eit) {
> +			fprintf(stderr, "%s(): non-NULL pointer detected "
> +				"during initialization", __FUNCTION__);
> +			return -1;
> +		}
> +		if(NULL == (curr_info->eit = calloc(curr_info->num_eits,
> +			sizeof(struct atsc_eit_info)))) {
> +			fprintf(stderr, "%s(): error calling calloc()\n",
> +				__FUNCTION__);
> +			return -1;
> +		}
> +		if(NULL == (curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN,
> +			sizeof(char)))) {
> +			fprintf(stderr, "%s(): error calling calloc()\n",
> +				__FUNCTION__);
> +			return -1;
> +		}
> +		curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
> +		curr_info->title_buf.buf_pos = 0;
> +
> +		if(NULL == (curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN,
> +			sizeof(char)))) {
> +			fprintf(stderr, "%s(): error calling calloc()\n",
> +				__FUNCTION__);
> +			return -1;
> +		}
> +		curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
> +		curr_info->msg_buf.buf_pos = 0;
> +
> +		for(k = 0; k < 7; k++) {
> +			curr_info->short_name[k] =
> +				get_bits((const uint8_t *)ch->short_name,
> +				k * 16, 16);
> +		}
> +		curr_info->service_type = ch->service_type;
> +		curr_info->major_num = ch->major_channel_number;
> +		curr_info->minor_num = ch->minor_channel_number;
> +		curr_info->tsid = ch->channel_TSID;
> +		curr_info->prog_num = ch->program_number;
> +		curr_info->src_id = ch->source_id;
> +		curr_info++;
> +		}
> +	} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
> +
> +	return 0;
> +}
> +
> +static int match_event(struct atsc_eit_info *eit, uint16_t event_id,
> +	struct atsc_event_info **event, uint8_t *curr_index)
> +{
> +	int j, k;
> +	struct atsc_eit_section_info *section;
> +
> +	if(NULL == eit || NULL == event || NULL == curr_index) {
> +		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +		return -1;
> +	}
> +
> +	for(j = 0; j < eit->num_eit_sections; j++) {
> +		section = &eit->section[j];
> +
> +		for(k = 0; k < section->num_events; k++) {
> +			if(section->events[k] && section->events[k]->id ==
> +				event_id) {
> +				*event = section->events[k];
> +				break;
> +			}
> +		}
> +		if(*event) {
> +			*curr_index = j;
> +			break;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int parse_message(struct atsc_channel_info *channel,
> +	struct atsc_ett_section *ett, struct atsc_event_info *event)
> +{
> +	int i, j;
> +	struct atsc_text *text;
> +	struct atsc_text_string *str;
> +
> +	if(NULL == ett || NULL == event || NULL == channel) {
> +		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +		return -1;
> +	}
> +
> +	text = atsc_ett_section_extended_text_message(ett);
> +	atsc_text_strings_for_each(text, str, i) {
> +		struct atsc_text_string_segment *seg;
> +
> +		atsc_text_string_segments_for_each(str, seg, j) {
> +			event->msg_pos = channel->msg_buf.buf_pos;
> +			if(0 > atsc_text_segment_decode(seg,
> +				(uint8_t **)&channel->msg_buf.string,
> +				(size_t *)&channel->msg_buf.buf_len,
> +				(size_t *)&channel->msg_buf.buf_pos)) {
> +				fprintf(stderr, "%s(): error calling "
> +					"atsc_text_segment_decode()\n",
> +					__FUNCTION__);
> +				return -1;
> +			}
> +			event->msg_len = 1 + channel->msg_buf.buf_pos -
> +				event->msg_pos;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int parse_ett(int dmxfd, int index, uint16_t pid)
> +{
> +	uint8_t curr_index;
> +	uint32_t section_pattern;
> +	const enum atsc_section_tag tag = stag_atsc_extended_text;
> +	struct atsc_eit_info *eit;
> +	struct atsc_ett_section *ett;
> +	struct atsc_channel_info *channel;
> +	struct atsc_event_info *event;
> +	struct atsc_eit_section_info *section;
> +	uint16_t source_id, event_id;
> +	int c, ret;
> +
> +	if(0xFFFF == guide.ett_pid[index]) {
> +		return 0;
> +	}
> +
> +	for(c = 0; c < guide.num_channels; c++) {
> +		channel = &guide.ch[c];
> +		eit = &channel->eit[index];
> +
> +		section_pattern = 0;
> +		while(section_pattern !=
> +			(uint32_t)((1 << eit->num_eit_sections) - 1)) {
> +			if(ctrl_c) {
> +				return 0;
> +			}
> +			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&ett);
> +			fprintf(stdout, ".");
> +			fflush(stdout);
> +			if(0 > ret) {
> +				fprintf(stderr, "%s(): error calling "
> +					"atsc_scan_table()\n", __FUNCTION__);
> +				return -1;
> +			}
> +			if(0 == ret) {
> +				fprintf(stdout, "no ETT %d in %d seconds\n",
> +					index, TIMEOUT);
> +				return 0;
> +			}
> +
> +			source_id = ett->ETM_source_id;
> +			event_id = ett->ETM_sub_id;
> +			if(source_id != channel->src_id) {
> +				continue;
> +			}
> +
> +			event = NULL;
> +			if(match_event(eit, event_id, &event, &curr_index)) {
> +				fprintf(stderr, "%s(): error calling "
> +					"match_event()\n", __FUNCTION__);
> +				return -1;
> +			}
> +			if(NULL == event) {
> +				continue;
> +			}
> +			if(section_pattern & (1 << curr_index)) {
> +				/* the section has been filled, so skip,
> +				 * not consider version yet
> +				 */
> +				continue;
> +			}
> +			if(event->msg_len) {
> +				/* the message has been filled */
> +				continue;
> +			}
> +
> +			if(parse_message(channel, ett, event)) {
> +				fprintf(stderr, "%s(): error calling "
> +					"parse_message()\n", __FUNCTION__);
> +				return -1;
> +			}
> +			section = &eit->section[curr_index];
> +			if(++section->num_received_etms == section->num_etms) {
> +				section_pattern |= 1 << curr_index;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int parse_events(struct atsc_channel_info *curr_info,
> +	struct atsc_eit_section *eit, struct atsc_eit_section_info *section)
> +{
> +	int i, j, k;
> +	struct atsc_eit_event *e;
> +	time_t start_time, end_time;
> +
> +	if(NULL == curr_info || NULL == eit) {
> +		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +		return -1;
> +	}
> +
> +	atsc_eit_section_events_for_each(eit, e, i) {
> +		struct atsc_text *title;
> +		struct atsc_text_string *str;
> +		struct atsc_event_info *e_info =
> +			&curr_info->e[curr_info->event_info_index];
> +
> +		if(0 == i && curr_info->last_event) {
> +			if(e->event_id == curr_info->last_event->id) {
> +				section->events[i] = NULL;
> +				/* skip if it's the same event spanning
> +				 * over sections
> +				 */
> +				continue;
> +			}
> +		}
> +		curr_info->event_info_index += 1;
> +		section->events[i] = e_info;
> +		e_info->id = e->event_id;
> +		start_time = atsctime_to_unixtime(e->start_time);
> +		end_time = start_time + e->length_in_seconds;
> +		localtime_r(&start_time, &e_info->start);
> +		localtime_r(&end_time, &e_info->end);
> +		if(0 != e->ETM_location && 3 != e->ETM_location) {
> +			/* FIXME assume 1 and 2 is interchangable as of now */
> +			section->num_etms++;
> +		}
> +
> +		title = atsc_eit_event_name_title_text(e);
> +		atsc_text_strings_for_each(title, str, j) {
> +			struct atsc_text_string_segment *seg;
> +
> +			atsc_text_string_segments_for_each(str, seg, k) {
> +				e_info->title_pos = curr_info->title_buf.buf_pos;
> +				if(0 > atsc_text_segment_decode(seg,
> +					(uint8_t **)&curr_info->title_buf.string,
> +					(size_t *)&curr_info->title_buf.buf_len,
> +					(size_t *)&curr_info->title_buf.buf_pos)) {
> +					fprintf(stderr, "%s(): error calling "
> +						"atsc_text_segment_decode()\n",
> +						__FUNCTION__);
> 
> 
> 
> Please don't wrap lines like this. It makes the code readability very
> bad. There is not much of a restriction to limit the no. of cols to
> 80, though at some points of times that helps in some ways.
> 
> Here but it really shows out that the wrapping to 80 cols makes it
> really bad. A very good example.
> 
> 
> +					return -1;
> +				}
> +				e_info->title_len = curr_info->title_buf.buf_pos -
> +					e_info->title_pos + 1;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int parse_eit(int dmxfd, int index, uint16_t pid)
> +{
> +	int num_sections;
> +	uint8_t section_num;
> +	uint8_t curr_channel_index;
> +	uint32_t section_pattern;
> +	const enum atsc_section_tag tag = stag_atsc_event_information;
> +	struct atsc_eit_section *eit;
> +	struct atsc_channel_info *curr_info;
> +	struct atsc_eit_info *eit_info;
> +	struct atsc_eit_section_info *section;
> +	uint16_t source_id;
> +	uint32_t eit_instance_pattern = 0;
> +	int i, k, ret;
> +
> +	while(eit_instance_pattern !=
> +		(uint32_t)((1 << guide.num_channels) - 1)) {
> +		source_id = 0xFFFF;
> +		section_pattern = 0;
> +		num_sections = -1;
> +
> +		do {
> +			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&eit);
> +			fprintf(stdout, ".");
> +			fflush(stdout);
> +			if(0 > ret) {
> +				fprintf(stderr, "%s(): error calling "
> +					"atsc_scan_table()\n", __FUNCTION__);
> +				return -1;
> +			}
> +			if(0 == ret) {
> +				fprintf(stdout, "no EIT %d in %d seconds\n",
> +					index, TIMEOUT);
> +				return 0;
> +			}
> +
> +			if(0xFFFF == source_id) {
> +			source_id = atsc_eit_section_source_id(eit);
> +			for(k = 0; k < guide.num_channels; k++) {
> +				if(source_id == guide.ch[k].src_id) {
> +					curr_info = &guide.ch[k];
> +					curr_channel_index = k;
> +					if(0 == index) {
> +						curr_info->last_event = NULL;
> +					}
> +					break;
> +				}
> +			}
> +			if(k == guide.num_channels) {
> +				fprintf(stderr, "%s(): cannot find source_id "
> +					"0x%04X in the EIT\n",
> +					__FUNCTION__, source_id);
> +				return -1;
> +			}
> +			} else {
> +				if(source_id !=
> +					atsc_eit_section_source_id(eit)) {
> +					continue;
> +				}
> +			}
> +			if(eit_instance_pattern & (1 << curr_channel_index)) {
> +				/* we have received this instance,
> +				 * so quit quick
> +				 */
> +				break;
> +			}
> +
> +			if(-1 == num_sections) {
> +				num_sections = 1 +
> +					eit->head.ext_head.last_section_number;
> +				if(32 < num_sections) {
> +					fprintf(stderr,
> +						"%s(): no support yet for "
> +						"tables having more than "
> +						"32 sections\n", __FUNCTION__);
> +					return -1;
> +				}
> +			} else {
> +				if(num_sections != 1 +
> +					eit->head.ext_head.last_section_number) {
> +					fprintf(stderr,
> +						"%s(): last section number "
> +						"does not match\n",
> +						__FUNCTION__);
> +					return -1;
> +				}
> +			}
> +			if(section_pattern &
> +				(1 << eit->head.ext_head.section_number)) {
> +				continue;
> +			}
> +			section_pattern |= 1 << eit->head.ext_head.section_number;
> +
> +			eit_info = &curr_info->eit[index];
> +			if(NULL == (eit_info->section =
> +				realloc(eit_info->section,
> +				(eit_info->num_eit_sections + 1) *
> +				sizeof(struct atsc_eit_section_info)))) {
> +				fprintf(stderr,
> +					"%s(): error calling realloc()\n",
> +					__FUNCTION__);
> +				return -1;
> +			}
> +			section_num = eit->head.ext_head.section_number;
> +			if(0 == eit_info->num_eit_sections) {
> +				eit_info->num_eit_sections = 1;
> +				section = eit_info->section;
> +			} else {
> +				/* have to sort it into section order
> +				 * (temporal order)
> +				 */
> +				for(i = 0; i < eit_info->num_eit_sections; i++) {
> +					if(eit_info->section[i].section_num >
> +						section_num) {
> +						break;
> +					}
> +				}
> +				memmove(&eit_info->section[i + 1],
> +					&eit_info->section[i],
> +					(eit_info->num_eit_sections - i) *
> +					sizeof(struct atsc_eit_section_info));
> +				section = &eit_info->section[i - 1];
> +				section = &eit_info->section[i];
> +				eit_info->num_eit_sections += 1;
> +			}
> +
> +			section->section_num = section_num;
> +			section->num_events = eit->num_events_in_section;
> +			section->num_etms = 0;
> +			section->num_received_etms = 0;
> +			if(NULL == (section->events = calloc(section->num_events,
> +				sizeof(struct atsc_event_info *)))) {
> +				fprintf(stderr, "%s(): error calling calloc()\n",
> +					__FUNCTION__);
> +				return -1;
> +			}
> +			if(parse_events(curr_info, eit, section)) {
> +				fprintf(stderr, "%s(): error calling "
> +					"parse_events()\n", __FUNCTION__);
> +				return -1;
> +			}
> +		} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
> +		eit_instance_pattern |= 1 << curr_channel_index;
> +	}
> +
> +	for(i = 0; i < guide.num_channels; i++) {
> +		struct atsc_channel_info *channel = &guide.ch[i];
> +		struct atsc_eit_info *ei = &channel->eit[index];
> +		struct atsc_eit_section_info *s;
> +
> +		if(0 == ei->num_eit_sections) {
> +			channel->last_event = NULL;
> +			continue;
> +		}
> +		s = &ei->section[ei->num_eit_sections - 1];
> +		/* BUG: it's incorrect when last section has no event */
> +		if(0 == s->num_events) {
> +			channel->last_event = NULL;
> +			continue;
> +		}
> +		channel->last_event = s->events[s->num_events - 1];
> +	}
> +
> +	return 0;
> +}
> +
> +static int parse_mgt(int dmxfd)
> +{
> +	const enum atsc_section_tag tag = stag_atsc_master_guide;
> +	struct atsc_mgt_section *mgt;
> +	struct atsc_mgt_table *t;
> +	int i, j, ret;
> +
> +	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&mgt);
> +	if(0 > ret) {
> +		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	if(0 == ret) {
> +		fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
> +		return 0;
> +	}
> +
> +	fprintf(stdout, "MGT table:\n");
> +	atsc_mgt_section_tables_for_each(mgt, t, i) {
> +		struct mgt_table_name table;
> +
> +	for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
> +		sizeof(struct mgt_table_name)); j++) {
> +		if(t->table_type > mgt_tab_name_array[j].range) {
> +			continue;
> +		}
> +		table = mgt_tab_name_array[j];
> +		if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
> +			mgt_tab_name_array[j].range) {
> +			j = -1;
> +		} else {
> +			j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
> +			if(0x017F == table.range) {
> +				guide.eit_pid[j] = t->table_type_PID;
> +			} else if (0x027F == table.range) {
> +				guide.ett_pid[j] = t->table_type_PID;
> +			}
> +		}
> +		break;
> +	}
> +
> +		fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X, %s", i,
> +		    t->table_type, t->table_type_PID, table.string);
> +		if(-1 != j) {
> +		    fprintf(stdout, " %d", j);
> +		}
> +		fprintf(stdout, "\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static int cleanup_guide(void)
> +{
> +	int i, j, k;
> +
> +	for(i = 0; i < guide.num_channels; i++) {
> +		struct atsc_channel_info *channel = &guide.ch[i];
> +
> +		if(channel->title_buf.string) {
> +			free(channel->title_buf.string);
> +		}
> +		if(channel->msg_buf.string) {
> +			free(channel->msg_buf.string);
> +		}
> +		for(j = 0; j < channel->num_eits; j++) {
> +			struct atsc_eit_info *eit = &channel->eit[j];
> +
> +			for(k = 0; k < eit->num_eit_sections; k++) {
> +				struct atsc_eit_section_info *section =
> +					&eit->section[k];
> +				if(section->num_events) {
> +					free(section->events);
> +				}
> +			}
> +			if(k) {
> +				free(eit->section);
> +			}
> +		}
> +		if(j) {
> +			free(channel->eit);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int print_events(struct atsc_channel_info *channel,
> +	struct atsc_eit_section_info *section)
> +{
> +	int m;
> +	char line[256];
> +
> +	if(NULL == section) {
> +		fprintf(stderr, "%s(): NULL pointer detected", __FUNCTION__);
> +		return -1;
> +	}
> +	for(m = 0; m < section->num_events; m++) {
> +		struct atsc_event_info *event =
> +			section->events[m];
> +
> +		if(NULL == event) {
> +			continue;
> +		}
> +		fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
> +			event->start.tm_hour, event->start.tm_min,
> +			event->end.tm_hour, event->end.tm_min);
> +		snprintf(line, event->title_len, "%s",
> +			&channel->title_buf.string[event->title_pos]);
> +		line[event->title_len] = '\0';
> +		fprintf(stdout, "%s\n", line);
> +		if(event->msg_len) {
> +			int len = event->msg_len;
> +			int pos = event->msg_pos;
> +			size_t part;
> +
> +			do {
> +				part = len > 255 ? 255 : len;
> +				snprintf(line, part, "%s",
> +					&channel->msg_buf.string[pos]);
> +				line[part] = '\0';
> +				fprintf(stdout, "%s", line);
> +				len -= part;
> +				pos += part;
> +			} while(0 < len);
> +			fprintf(stdout, "\n");
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int print_guide(void)
> +{
> +	int i, j, k;
> +
> +	fprintf(stdout, "%s\n", separator);
> +	for(i = 0; i < guide.num_channels; i++) {
> +		struct atsc_channel_info *channel = &guide.ch[i];
> +
> +		fprintf(stdout, "%d.%d  %s\n", channel->major_num,
> +			channel->minor_num, channel->short_name);
> +		for(j = 0; j < channel->num_eits; j++) {
> +			struct atsc_eit_info *eit = &channel->eit[j];
> +
> +			for(k = 0; k < eit->num_eit_sections; k++) {
> +				struct atsc_eit_section_info *section =
> +					&eit->section[k];
> +				if(print_events(channel, section)) {
> +					fprintf(stderr, "%s(): error calling "
> +						"print_events()\n", __FUNCTION__);
> +					return -1;
> +				}
> +			}
> +		}
> +		fprintf(stdout, "%s\n", separator);
> +	}
> +
> +	return 0;
> +}
> +
> +static int open_demux(int *dmxfd)
> +{
> +	if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
> +		fprintf(stderr, "%s(): error calling dvbdemux_open_demux()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +static int close_demux(int dmxfd)
> +{
> +	if(dvbdemux_stop(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling dvbdemux_stop()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +/* used other utilities as template and generalized here */
> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
> +	void **table_section)
> +{
> +	uint8_t filter[18];
> +	uint8_t mask[18];
> +	unsigned char sibuf[4096];
> +	int size;
> +	int ret;
> +	struct pollfd pollfd;
> +	struct section *section;
> +	struct section_ext *section_ext;
> +	struct atsc_section_psip *psip;
> +
> +	/* create a section filter for the table */
> +	memset(filter, 0, sizeof(filter));
> +	memset(mask, 0, sizeof(mask));
> +	filter[0] = tag;
> +	mask[0] = 0xFF;
> +	if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
> +		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	/* poll for data */
> +	pollfd.fd = dmxfd;
> +	pollfd.events = POLLIN | POLLERR |POLLPRI;
> +	if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
> +		if(ctrl_c) {
> +			return 0;
> +		}
> +		fprintf(stderr, "%s(): error calling poll()\n", __FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(0 == ret) {
> +		return 0;
> +	}
> +
> +	/* read it */
> +	if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
> +		fprintf(stderr, "%s(): error calling read()\n", __FUNCTION__);
> +		return -1;
> +	}
> +
> +	/* parse section */
> +	section = section_codec(sibuf, size);
> +	if(NULL == section) {
> +		fprintf(stderr, "%s(): error calling section_codec()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	section_ext = section_ext_decode(section, 0);
> +	if(NULL == section_ext) {
> +		fprintf(stderr, "%s(): error calling section_ext_decode()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	psip = atsc_section_psip_decode(section_ext);
> +	if(NULL == psip) {
> +		fprintf(stderr,
> +			"%s(): error calling atsc_section_psip_decode()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	*table_section = table_callback[tag & 0x0F](psip);
> +	if(NULL == *table_section) {
> +		fprintf(stderr, "%s(): error decode table section\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	return 1;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	int i, dmxfd;
> +	struct dvbfe_handle *fe;
> +
> +	program = argv[0];
> +
> +	if(1 == argc) {
> +		usage();
> +		exit(-1);
> +	}
> +
> +	for( ; ; ) {
> +		char c;
> +
> +		if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
> +			break;
> +		}
> +
> +		switch(c) {
> +		case 'a':
> +			adapter = strtoll(optarg, NULL, 0);
> +			break;
> +
> +		case 'f':
> +			frequency = strtol(optarg, NULL, 0);
> +			break;
> +
> +		case 'p':
> +			period = strtol(optarg, NULL, 0);
> +			/* each table covers 3 hours */
> +			if((3 * MAX_NUM_EVENT_TABLES) < period) {
> +				period = 3 * MAX_NUM_EVENT_TABLES;
> +			}
> +			break;
> +
> +		case 'm':
> +			/* just stub, so far ATSC only has VSB_8 */
> +			modulation = optarg;
> +			break;
> +
> +		case 't':
> +			enable_ett = 1;
> +			break;
> +
> +		case 'h':
> +			help();
> +			exit(0);
> +
> +		default:
> +			usage();
> +			exit(-1);
> +		}
> +	}
> +
> +	memset(separator, '-', sizeof(separator));
> +	separator[79] = '\0';
> +	memset(&guide, 0, sizeof(struct atsc_virtual_channels_info));
> +	memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
> +	memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
> +
> +	if(open_frontend(&fe)) {
> +		fprintf(stderr, "%s(): error calling open_frontend()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(open_demux(&dmxfd)) {
> +		fprintf(stderr, "%s(): error calling open_demux()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(parse_stt(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling parse_stt()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(parse_mgt(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling parse_mgt()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(parse_tvct(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling parse_tvct()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +#ifdef ENABLE_RRT
> +	if(parse_rrt(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling parse_rrt()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +#endif
> +
> +	fprintf(stdout, "receiving EIT ");
> +	for(i = 0; i < guide.ch[0].num_eits; i++) {
> +		if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
> +			fprintf(stderr, "%s(): error calling parse_eit()\n",
> +				__FUNCTION__);
> +			return -1;
> +		}
> +	}
> +	fprintf(stdout, "\n");
> +
> +	old_handler = signal(SIGINT, int_handler);
> +	if(enable_ett) {
> +		fprintf(stdout, "receiving ETT ");
> +		for(i = 0; i < guide.ch[0].num_eits; i++) {
> +			if(0xFFFF != guide.ett_pid[i]) {
> +				if(parse_ett(dmxfd, i, guide.ett_pid[i])) {
> +					fprintf(stderr, "%s(): error calling "
> +						"parse_eit()\n", __FUNCTION__);
> +					return -1;
> +				}
> +			}
> +			if(ctrl_c) {
> +				break;
> +			}
> +		}
> +		fprintf(stdout, "\n");
> +	}
> +	signal(SIGINT, old_handler);
> +
> +	if(print_guide()) {
> +		fprintf(stderr, "%s(): error calling print_guide()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(cleanup_guide()) {
> +		fprintf(stderr, "%s(): error calling cleanup_guide()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(close_demux(dmxfd)) {
> +		fprintf(stderr, "%s(): error calling close_demux()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	if(close_frontend(fe)) {
> +		fprintf(stderr, "%s(): error calling close_demux()\n",
> +			__FUNCTION__);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> diff -uprN dvb-apps/util/atsc_epg/Makefile dvb-apps_new/util/atsc_epg/Makefile
> --- dvb-apps/util/atsc_epg/Makefile	1969-12-31 18:00:00.000000000 -0600
> +++ dvb-apps_new/util/atsc_epg/Makefile	2009-06-18 20:11:58.362985962 -0500
> @@ -0,0 +1,16 @@
> +# Makefile for linuxtv.org dvb-apps/util/atsc_epg
> +
> +binaries = atsc_epg
> +
> +inst_bin = $(binaries)
> +
> +CPPFLAGS += -I../../lib -std=c99 -D_POSIX_SOURCE
> +#LDFLAGS  += -static -L../../lib/libdvbapi -L../../lib/libucsi
> +LDFLAGS  += -L../../lib/libdvbapi -L../../lib/libucsi
> +LDLIBS   += -ldvbapi -lucsi
> +
> +.PHONY: all
> +
> +all: $(binaries)
> +
> +include ../../Make.rules
> diff -uprN dvb-apps/util/atsc_epg/README dvb-apps_new/util/atsc_epg/README
> --- dvb-apps/util/atsc_epg/README	1969-12-31 18:00:00.000000000 -0600
> +++ dvb-apps_new/util/atsc_epg/README	2009-06-18 20:33:47.836924378 -0500
> @@ -0,0 +1,12 @@
> +Hi there,
> +
> +atsc_epg is a small utility for obtaining information such as programs, EPG
> +(electronic program guide) from an ATSC channel.
> +
> +Pulling the detailed information, i.e., option '-t', may take fairly long
> +time, or never ending, which is a bug of the PSIP generator. Ctrl+C can be
> +used to abort and the received parts will be printed.
> +
> +Enjoy,
> +Yufei
> +
> diff -uprN dvb-apps/util/Makefile dvb-apps_new/util/Makefile
> --- dvb-apps/util/Makefile	2009-06-18 19:43:30.034986539 -0500
> +++ dvb-apps_new/util/Makefile	2009-06-18 20:11:41.169986806 -0500
> @@ -3,6 +3,7 @@
>  .PHONY: all clean install
> 
>  all clean install:
> +	$(MAKE) -C atsc_epg $@
>  	$(MAKE) -C av7110_loadkeys $@
>  	$(MAKE) -C dib3000-watch $@
>  	$(MAKE) -C dst-utils $@
> 
> 
> Regards,
> Manu


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [Patch] dvb-apps: code cleanup and bug fix.
  2009-06-20  7:30             ` Manu Abraham
  2009-06-20 13:30               ` Yufei Yuan
@ 2009-06-20 17:15               ` Yufei Yuan
  2009-06-20 17:31                 ` Yufei Yuan
  2009-06-22 23:43               ` [Patch] New utility program atsc_epg added to dvb-apps utility suite Yufei Yuan
  2 siblings, 1 reply; 22+ messages in thread
From: Yufei Yuan @ 2009-06-20 17:15 UTC (permalink / raw)
  To: Manu Abraham; +Cc: Linux Media Mailing List

This patch is against dvb-apps 1281. Following is what has been done:

1. atsc_epg bug fix: when ETM message gets longer than 256 characters, the last
character was chopped, due to incorrect calling to snprintf().
2. atsc_epg code cleanup:
  - white space added after keywords;
  - hard wrap around column 80 removed;
  - one-line conditional statement now w/o brackets.
3. scan Makefile workaround for building in gcc4.4/kernel 2.6.30 was not picked up in 1279, include again.

Regards,

Signed-off-by: Yufei Yuan <yfyuan@gmail.com>

diff -upr dvb-apps/util/atsc_epg/atsc_epg.c dvb-apps_local/util/atsc_epg/atsc_epg.c
--- dvb-apps/util/atsc_epg/atsc_epg.c	2009-06-20 11:54:20.393986790 -0500
+++ dvb-apps_local/util/atsc_epg/atsc_epg.c	2009-06-20 12:09:08.000000000 -0500
@@ -168,9 +168,8 @@ void *(*table_callback[16])(struct atsc_
 
 static void int_handler(int sig_num)
 {
-	if(SIGINT != sig_num) {
+	if (SIGINT != sig_num)
 		return;
-	}
 	ctrl_c = 1;
 }
 
@@ -219,8 +218,9 @@ static void help(void)
 
 static int close_frontend(struct dvbfe_handle *fe)
 {
-	if(NULL == fe) {
+	if (NULL == fe) {
 		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+		return -1;
 	}
 
 	dvbfe_close(fe);
@@ -232,22 +232,20 @@ static int open_frontend(struct dvbfe_ha
 {
 	struct dvbfe_info fe_info;
 
-	if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
-		fprintf(stderr, "%s(): error calling dvbfe_open()\n",
-			__FUNCTION__);
+	if (NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
+		fprintf(stderr, "%s(): error calling dvbfe_open()\n", __FUNCTION__);
 		return -1;
 	}
 	dvbfe_get_info(*fe, 0, &fe_info, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
-	if(DVBFE_TYPE_ATSC != fe_info.type) {
-		fprintf(stderr, "%s(): only ATSC frontend supported currently\n",
-			__FUNCTION__);
+	if (DVBFE_TYPE_ATSC != fe_info.type) {
+		fprintf(stderr, "%s(): only ATSC frontend supported currently\n", __FUNCTION__);
 		return -1;
 	}
 	fe_info.feparams.frequency = frequency;
 	fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
 	fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
 	fprintf(stdout, "tuning to %d Hz, please wait...\n", frequency);
-	if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
+	if (dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
 		fprintf(stderr, "%s(): cannot lock to %d Hz in %d seconds\n",
 			__FUNCTION__, frequency, TIMEOUT);
 		return -1;
@@ -257,7 +255,7 @@ static int open_frontend(struct dvbfe_ha
 	return 0;
 }
 
-#if ENABLE_RRT
+#ifdef ENABLE_RRT
 /* this is untested as since this part of the library is broken */
 static int parse_rrt(int dmxfd)
 {
@@ -270,20 +268,18 @@ static int parse_rrt(int dmxfd)
 	i = 0;
 	fprintf(stdout, "waiting for RRT: ");
 	fflush(stdout);
-	while(i < RRT_TIMEOUT) {
+	while (i < RRT_TIMEOUT) {
 		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&rrt);
-		if(0 > ret) {
-			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
-				__FUNCTION__);
+		if (0 > ret) {
+			fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
 			return -1;
 		}
-		if(0 == ret) {
-			if(RRT_TIMEOUT > i) {
+		if (0 == ret) {
+			if (RRT_TIMEOUT > i) {
 				fprintf(stdout, ".");
 				fflush(stdout);
 			} else {
-				fprintf(stdout, "\nno RRT in %d seconds\n",
-					RRT_TIMEOUT);
+				fprintf(stdout, "\nno RRT in %d seconds\n", RRT_TIMEOUT);
 				return 0;
 			}
 			i += TIMEOUT;
@@ -301,14 +297,13 @@ static int parse_rrt(int dmxfd)
 		atsc_text_string_segments_for_each(atsc_str, seg, j) {
 			const char *c;
 			int k;
-			if(seg->mode < 0x3E) {
-				fprintf(stderr, "%s(): text mode of 0x%02X "
-					"not supported yet\n",
-					__FUNCTION__, seg->mode);
+
+			if (seg->mode < 0x3E) {
+				fprintf(stderr, "%s(): text mode of 0x%02X not supported yet\n", __FUNCTION__, seg->mode);
 				return -1;
 			}
 			c = (const char *)atsc_text_string_segment_bytes(seg);
-			for(k = 0; k < seg->number_bytes; k++) {
+			for (k = 0; k < seg->number_bytes; k++) {
 				fprintf(stdout, "%c", c[k]);
 			}
 		}
@@ -327,12 +322,11 @@ static int parse_stt(int dmxfd)
 	int ret;
 
 	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&stt);
-	if(0 > ret) {
-		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
-			__FUNCTION__);
+	if (0 > ret) {
+		fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
 		return -1;
 	}
-	if(0 == ret) {
+	if (0 == ret) {
 		fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
 		return 0;
 	}
@@ -360,99 +354,86 @@ static int parse_tvct(int dmxfd)
 
 	do {
 		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&tvct);
-		if(0 > ret) {
-			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
-			__FUNCTION__);
+		if (0 > ret) {
+			fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
 			return -1;
 		}
-		if(0 == ret) {
+		if (0 == ret) {
 			fprintf(stdout, "no TVCT in %d seconds\n", TIMEOUT);
 			return 0;
 		}
 
-		if(-1 == num_sections) {
+		if (-1 == num_sections) {
 			num_sections = 1 + tvct->head.ext_head.last_section_number;
-			if(32 < num_sections) {
-				fprintf(stderr, "%s(): no support yet for "
-					"tables having more than 32 sections\n",
-					__FUNCTION__);
+			if (32 < num_sections) {
+				fprintf(stderr, "%s(): no support yet for tables having more than 32 sections\n", __FUNCTION__);
 				return -1;
 			}
 		} else {
-			if(num_sections !=
+			if (num_sections !=
 				1 + tvct->head.ext_head.last_section_number) {
-				fprintf(stderr,
-					"%s(): last section number does not match\n",
-					__FUNCTION__);
+				fprintf(stderr, "%s(): last section number does not match\n", __FUNCTION__);
 				return -1;
 			}
 		}
-		if(section_pattern & (1 << tvct->head.ext_head.section_number)) {
+		if (section_pattern & (1 << tvct->head.ext_head.section_number))
 			continue;
-		}
+
 		section_pattern |= 1 << tvct->head.ext_head.section_number;
 
-		if(MAX_NUM_CHANNELS < guide.num_channels +
+		if (MAX_NUM_CHANNELS < guide.num_channels +
 			tvct->num_channels_in_section) {
-			fprintf(stderr, "%s(): no support for more than %d "
-				"virtual channels in a pyhsical channel\n",
-				__FUNCTION__, MAX_NUM_CHANNELS);
+			fprintf(stderr, "%s(): no support for more than %d virtual channels in a pyhsical channel\n", __FUNCTION__, MAX_NUM_CHANNELS);
 			return -1;
 		}
 		curr_info = &guide.ch[guide.num_channels];
 		guide.num_channels += tvct->num_channels_in_section;
 
-	atsc_tvct_section_channels_for_each(tvct, ch, i) {
-		/* initialize the curr_info structure */
-		/* each EIT covers 3 hours */
-		curr_info->num_eits = (period / 3) + !!(period % 3);
-		while (curr_info->num_eits &&
-			(0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
-			curr_info->num_eits -= 1;
-		}
-		if(curr_info->eit) {
-			fprintf(stderr, "%s(): non-NULL pointer detected "
-				"during initialization", __FUNCTION__);
-			return -1;
-		}
-		if(NULL == (curr_info->eit = calloc(curr_info->num_eits,
-			sizeof(struct atsc_eit_info)))) {
-			fprintf(stderr, "%s(): error calling calloc()\n",
-				__FUNCTION__);
-			return -1;
-		}
-		if(NULL == (curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN,
-			sizeof(char)))) {
-			fprintf(stderr, "%s(): error calling calloc()\n",
-				__FUNCTION__);
-			return -1;
-		}
-		curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
-		curr_info->title_buf.buf_pos = 0;
+		atsc_tvct_section_channels_for_each(tvct, ch, i) {
+			/* initialize the curr_info structure */
+			/* each EIT covers 3 hours */
+			curr_info->num_eits = (period / 3) + !!(period % 3);
+			while (curr_info->num_eits &&
+				(0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
+				curr_info->num_eits -= 1;
+			}
+			if (curr_info->eit) {
+				fprintf(stderr, "%s(): non-NULL pointer detected during initialization", __FUNCTION__);
+				return -1;
+			}
+			curr_info->eit = calloc(curr_info->num_eits, sizeof(struct atsc_eit_info));
+			if (NULL == curr_info->eit) {
+				fprintf(stderr, "%s(): error calling calloc()\n", __FUNCTION__);
+				return -1;
+			}
+			curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN, sizeof(char));
+			if (NULL == curr_info->title_buf.string) {
+				fprintf(stderr, "%s(): error calling calloc()\n", __FUNCTION__);
+				return -1;
+			}
+			curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
+			curr_info->title_buf.buf_pos = 0;
 
-		if(NULL == (curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN,
-			sizeof(char)))) {
-			fprintf(stderr, "%s(): error calling calloc()\n",
-				__FUNCTION__);
-			return -1;
-		}
-		curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
-		curr_info->msg_buf.buf_pos = 0;
+			curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN, sizeof(char));
+			if (NULL == curr_info->msg_buf.string) {
+				fprintf(stderr, "%s(): error calling calloc()\n", __FUNCTION__);
+				return -1;
+			}
+			curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
+			curr_info->msg_buf.buf_pos = 0;
 
-		for(k = 0; k < 7; k++) {
-			curr_info->short_name[k] =
-				get_bits((const uint8_t *)ch->short_name,
-				k * 16, 16);
-		}
-		curr_info->service_type = ch->service_type;
-		curr_info->major_num = ch->major_channel_number;
-		curr_info->minor_num = ch->minor_channel_number;
-		curr_info->tsid = ch->channel_TSID;
-		curr_info->prog_num = ch->program_number;
-		curr_info->src_id = ch->source_id;
-		curr_info++;
+			for (k = 0; k < 7; k++)
+				curr_info->short_name[k] =
+					get_bits((const uint8_t *)ch->short_name, k * 16, 16);
+			curr_info->service_type = ch->service_type;
+			curr_info->major_num = ch->major_channel_number;
+			curr_info->minor_num = ch->minor_channel_number;
+			curr_info->tsid = ch->channel_TSID;
+			curr_info->prog_num = ch->program_number;
+			curr_info->src_id = ch->source_id;
+			curr_info++;
 		}
-	} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
+	} while (section_pattern != (uint32_t)((1 << num_sections) - 1));
 
 	return 0;
 }
@@ -463,22 +444,21 @@ static int match_event(struct atsc_eit_i
 	int j, k;
 	struct atsc_eit_section_info *section;
 
-	if(NULL == eit || NULL == event || NULL == curr_index) {
+	if (NULL == eit || NULL == event || NULL == curr_index) {
 		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
 		return -1;
 	}
 
-	for(j = 0; j < eit->num_eit_sections; j++) {
+	for (j = 0; j < eit->num_eit_sections; j++) {
 		section = &eit->section[j];
 
-		for(k = 0; k < section->num_events; k++) {
-			if(section->events[k] && section->events[k]->id ==
-				event_id) {
+		for (k = 0; k < section->num_events; k++) {
+			if (section->events[k] && section->events[k]->id == event_id) {
 				*event = section->events[k];
 				break;
 			}
 		}
-		if(*event) {
+		if (*event) {
 			*curr_index = j;
 			break;
 		}
@@ -494,7 +474,7 @@ static int parse_message(struct atsc_cha
 	struct atsc_text *text;
 	struct atsc_text_string *str;
 
-	if(NULL == ett || NULL == event || NULL == channel) {
+	if (NULL == ett || NULL == event || NULL == channel) {
 		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
 		return -1;
 	}
@@ -505,17 +485,11 @@ static int parse_message(struct atsc_cha
 
 		atsc_text_string_segments_for_each(str, seg, j) {
 			event->msg_pos = channel->msg_buf.buf_pos;
-			if(0 > atsc_text_segment_decode(seg,
-				(uint8_t **)&channel->msg_buf.string,
-				(size_t *)&channel->msg_buf.buf_len,
-				(size_t *)&channel->msg_buf.buf_pos)) {
-				fprintf(stderr, "%s(): error calling "
-					"atsc_text_segment_decode()\n",
-					__FUNCTION__);
+			if (0 > atsc_text_segment_decode(seg, (uint8_t **)&channel->msg_buf.string, (size_t *)&channel->msg_buf.buf_len, (size_t *)&channel->msg_buf.buf_pos)) {
+				fprintf(stderr, "%s(): error calling atsc_text_segment_decode()\n", __FUNCTION__);
 				return -1;
 			}
-			event->msg_len = 1 + channel->msg_buf.buf_pos -
-				event->msg_pos;
+			event->msg_len = channel->msg_buf.buf_pos - event->msg_pos;
 		}
 	}
 
@@ -535,69 +509,58 @@ static int parse_ett(int dmxfd, int inde
 	uint16_t source_id, event_id;
 	int c, ret;
 
-	if(0xFFFF == guide.ett_pid[index]) {
+	if (0xFFFF == guide.ett_pid[index])
 		return 0;
-	}
 
-	for(c = 0; c < guide.num_channels; c++) {
+	for (c = 0; c < guide.num_channels; c++) {
 		channel = &guide.ch[c];
 		eit = &channel->eit[index];
 
 		section_pattern = 0;
-		while(section_pattern !=
-			(uint32_t)((1 << eit->num_eit_sections) - 1)) {
-			if(ctrl_c) {
+		while (section_pattern != (uint32_t)((1 << eit->num_eit_sections) - 1)) {
+			if (ctrl_c)
 				return 0;
-			}
+
 			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&ett);
 			fprintf(stdout, ".");
 			fflush(stdout);
-			if(0 > ret) {
-				fprintf(stderr, "%s(): error calling "
-					"atsc_scan_table()\n", __FUNCTION__);
+			if (0 > ret) {
+				fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
 				return -1;
 			}
-			if(0 == ret) {
-				fprintf(stdout, "no ETT %d in %d seconds\n",
-					index, TIMEOUT);
+			if (0 == ret) {
+				fprintf(stdout, "no ETT %d in %d seconds\n", index, TIMEOUT);
 				return 0;
 			}
 
 			source_id = ett->ETM_source_id;
 			event_id = ett->ETM_sub_id;
-			if(source_id != channel->src_id) {
+			if (source_id != channel->src_id)
 				continue;
-			}
 
 			event = NULL;
-			if(match_event(eit, event_id, &event, &curr_index)) {
-				fprintf(stderr, "%s(): error calling "
-					"match_event()\n", __FUNCTION__);
+			if (match_event(eit, event_id, &event, &curr_index)) {
+				fprintf(stderr, "%s(): error calling match_event()\n", __FUNCTION__);
 				return -1;
 			}
-			if(NULL == event) {
+			if (NULL == event)
 				continue;
-			}
-			if(section_pattern & (1 << curr_index)) {
-				/* the section has been filled, so skip,
-				 * not consider version yet
-				 */
+
+			/* the section has been filled, so skip, not consider version yet */
+			if (section_pattern & (1 << curr_index))
 				continue;
-			}
-			if(event->msg_len) {
-				/* the message has been filled */
+
+			/* the message has been filled */
+			if (event->msg_len)
 				continue;
-			}
 
-			if(parse_message(channel, ett, event)) {
-				fprintf(stderr, "%s(): error calling "
-					"parse_message()\n", __FUNCTION__);
+			if (parse_message(channel, ett, event)) {
+				fprintf(stderr, "%s(): error calling parse_message()\n", __FUNCTION__);
 				return -1;
 			}
 			section = &eit->section[curr_index];
-			if(++section->num_received_etms == section->num_etms) {
+			if (++section->num_received_etms == section->num_etms)
 				section_pattern |= 1 << curr_index;
-			}
 		}
 	}
 
@@ -611,7 +574,7 @@ static int parse_events(struct atsc_chan
 	struct atsc_eit_event *e;
 	time_t start_time, end_time;
 
-	if(NULL == curr_info || NULL == eit) {
+	if (NULL == curr_info || NULL == eit) {
 		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
 		return -1;
 	}
@@ -619,15 +582,12 @@ static int parse_events(struct atsc_chan
 	atsc_eit_section_events_for_each(eit, e, i) {
 		struct atsc_text *title;
 		struct atsc_text_string *str;
-		struct atsc_event_info *e_info =
-			&curr_info->e[curr_info->event_info_index];
+		struct atsc_event_info *e_info = &curr_info->e[curr_info->event_info_index];
 
-		if(0 == i && curr_info->last_event) {
-			if(e->event_id == curr_info->last_event->id) {
+		if (0 == i && curr_info->last_event) {
+			if (e->event_id == curr_info->last_event->id) {
 				section->events[i] = NULL;
-				/* skip if it's the same event spanning
-				 * over sections
-				 */
+				/* skip if it's the same event spanning over sections */
 				continue;
 			}
 		}
@@ -638,10 +598,9 @@ static int parse_events(struct atsc_chan
 		end_time = start_time + e->length_in_seconds;
 		localtime_r(&start_time, &e_info->start);
 		localtime_r(&end_time, &e_info->end);
-		if(0 != e->ETM_location && 3 != e->ETM_location) {
-			/* FIXME assume 1 and 2 is interchangable as of now */
+		/* FIXME assume 1 and 2 is interchangable as of now */
+		if (0 != e->ETM_location && 3 != e->ETM_location)
 			section->num_etms++;
-		}
 
 		title = atsc_eit_event_name_title_text(e);
 		atsc_text_strings_for_each(title, str, j) {
@@ -649,17 +608,11 @@ static int parse_events(struct atsc_chan
 
 			atsc_text_string_segments_for_each(str, seg, k) {
 				e_info->title_pos = curr_info->title_buf.buf_pos;
-				if(0 > atsc_text_segment_decode(seg,
-					(uint8_t **)&curr_info->title_buf.string,
-					(size_t *)&curr_info->title_buf.buf_len,
-					(size_t *)&curr_info->title_buf.buf_pos)) {
-					fprintf(stderr, "%s(): error calling "
-						"atsc_text_segment_decode()\n",
-						__FUNCTION__);
+				if (0 > atsc_text_segment_decode(seg, (uint8_t **)&curr_info->title_buf.string, (size_t *)&curr_info->title_buf.buf_len, (size_t *)&curr_info->title_buf.buf_pos)) {
+					fprintf(stderr, "%s(): error calling atsc_text_segment_decode()\n", __FUNCTION__);
 					return -1;
 				}
-				e_info->title_len = curr_info->title_buf.buf_pos -
-					e_info->title_pos + 1;
+				e_info->title_len = curr_info->title_buf.buf_pos - e_info->title_pos;
 			}
 		}
 	}
@@ -682,8 +635,7 @@ static int parse_eit(int dmxfd, int inde
 	uint32_t eit_instance_pattern = 0;
 	int i, k, ret;
 
-	while(eit_instance_pattern !=
-		(uint32_t)((1 << guide.num_channels) - 1)) {
+	while (eit_instance_pattern != (uint32_t)((1 << guide.num_channels) - 1)) {
 		source_id = 0xFFFF;
 		section_pattern = 0;
 		num_sections = -1;
@@ -692,102 +644,71 @@ static int parse_eit(int dmxfd, int inde
 			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&eit);
 			fprintf(stdout, ".");
 			fflush(stdout);
-			if(0 > ret) {
-				fprintf(stderr, "%s(): error calling "
-					"atsc_scan_table()\n", __FUNCTION__);
+			if (0 > ret) {
+				fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
 				return -1;
 			}
-			if(0 == ret) {
-				fprintf(stdout, "no EIT %d in %d seconds\n",
-					index, TIMEOUT);
+			if (0 == ret) {
+				fprintf(stdout, "no EIT %d in %d seconds\n", index, TIMEOUT);
 				return 0;
 			}
 
-			if(0xFFFF == source_id) {
+			if (0xFFFF == source_id) {
 			source_id = atsc_eit_section_source_id(eit);
-			for(k = 0; k < guide.num_channels; k++) {
-				if(source_id == guide.ch[k].src_id) {
+			for (k = 0; k < guide.num_channels; k++) {
+				if (source_id == guide.ch[k].src_id) {
 					curr_info = &guide.ch[k];
 					curr_channel_index = k;
-					if(0 == index) {
+					if (0 == index)
 						curr_info->last_event = NULL;
-					}
 					break;
 				}
 			}
-			if(k == guide.num_channels) {
-				fprintf(stderr, "%s(): cannot find source_id "
-					"0x%04X in the EIT\n",
-					__FUNCTION__, source_id);
+			if (k == guide.num_channels) {
+				fprintf(stderr, "%s(): cannot find source_id 0x%04X in the EIT\n", __FUNCTION__, source_id);
 				return -1;
 			}
 			} else {
-				if(source_id !=
-					atsc_eit_section_source_id(eit)) {
+				if (source_id != atsc_eit_section_source_id(eit))
 					continue;
-				}
 			}
-			if(eit_instance_pattern & (1 << curr_channel_index)) {
-				/* we have received this instance,
-				 * so quit quick
-				 */
+			/* if we have received this instance, quit quick */
+			if (eit_instance_pattern & (1 << curr_channel_index))
 				break;
-			}
 
-			if(-1 == num_sections) {
-				num_sections = 1 +
-					eit->head.ext_head.last_section_number;
-				if(32 < num_sections) {
-					fprintf(stderr,
-						"%s(): no support yet for "
-						"tables having more than "
-						"32 sections\n", __FUNCTION__);
+			if (-1 == num_sections) {
+				num_sections = 1 + eit->head.ext_head.last_section_number;
+				if (32 < num_sections) {
+					fprintf(stderr, "%s(): no support yet for tables having more than 32 sections\n", __FUNCTION__);
 					return -1;
 				}
 			} else {
-				if(num_sections != 1 +
-					eit->head.ext_head.last_section_number) {
-					fprintf(stderr,
-						"%s(): last section number "
-						"does not match\n",
-						__FUNCTION__);
+				if (num_sections != 1 + eit->head.ext_head.last_section_number) {
+					fprintf(stderr, "%s(): last section number does not match\n", __FUNCTION__);
 					return -1;
 				}
 			}
-			if(section_pattern &
-				(1 << eit->head.ext_head.section_number)) {
+			if (section_pattern & (1 << eit->head.ext_head.section_number))
 				continue;
-			}
 			section_pattern |= 1 << eit->head.ext_head.section_number;
 
 			eit_info = &curr_info->eit[index];
-			if(NULL == (eit_info->section =
-				realloc(eit_info->section,
-				(eit_info->num_eit_sections + 1) *
-				sizeof(struct atsc_eit_section_info)))) {
-				fprintf(stderr,
-					"%s(): error calling realloc()\n",
-					__FUNCTION__);
+			eit_info->section = realloc(eit_info->section, (eit_info->num_eit_sections + 1) * sizeof(struct atsc_eit_section_info));
+			if (NULL == eit_info->section) {
+				fprintf(stderr, "%s(): error calling realloc()\n", __FUNCTION__);
 				return -1;
 			}
 			section_num = eit->head.ext_head.section_number;
-			if(0 == eit_info->num_eit_sections) {
+			if (0 == eit_info->num_eit_sections) {
 				eit_info->num_eit_sections = 1;
 				section = eit_info->section;
 			} else {
-				/* have to sort it into section order
-				 * (temporal order)
-				 */
-				for(i = 0; i < eit_info->num_eit_sections; i++) {
-					if(eit_info->section[i].section_num >
-						section_num) {
+				/* have to sort it into section order (temporal order) */
+				for (i = 0; i < eit_info->num_eit_sections; i++) {
+					if (eit_info->section[i].section_num > section_num)
 						break;
-					}
 				}
-				memmove(&eit_info->section[i + 1],
-					&eit_info->section[i],
-					(eit_info->num_eit_sections - i) *
-					sizeof(struct atsc_eit_section_info));
+				memmove(&eit_info->section[i + 1], &eit_info->section[i], (eit_info->num_eit_sections - i) * sizeof(struct atsc_eit_section_info));
 				section = &eit_info->section[i - 1];
 				section = &eit_info->section[i];
 				eit_info->num_eit_sections += 1;
@@ -797,33 +718,31 @@ static int parse_eit(int dmxfd, int inde
 			section->num_events = eit->num_events_in_section;
 			section->num_etms = 0;
 			section->num_received_etms = 0;
-			if(NULL == (section->events = calloc(section->num_events,
-				sizeof(struct atsc_event_info *)))) {
-				fprintf(stderr, "%s(): error calling calloc()\n",
-					__FUNCTION__);
+			section->events = calloc(section->num_events, sizeof(struct atsc_event_info *));
+			if (NULL == section->events) {
+				fprintf(stderr, "%s(): error calling calloc()\n", __FUNCTION__);
 				return -1;
 			}
-			if(parse_events(curr_info, eit, section)) {
-				fprintf(stderr, "%s(): error calling "
-					"parse_events()\n", __FUNCTION__);
+			if (parse_events(curr_info, eit, section)) {
+				fprintf(stderr, "%s(): error calling parse_events()\n", __FUNCTION__);
 				return -1;
 			}
-		} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
+		} while (section_pattern != (uint32_t)((1 << num_sections) - 1));
 		eit_instance_pattern |= 1 << curr_channel_index;
 	}
 
-	for(i = 0; i < guide.num_channels; i++) {
+	for (i = 0; i < guide.num_channels; i++) {
 		struct atsc_channel_info *channel = &guide.ch[i];
 		struct atsc_eit_info *ei = &channel->eit[index];
 		struct atsc_eit_section_info *s;
 
-		if(0 == ei->num_eit_sections) {
+		if (0 == ei->num_eit_sections) {
 			channel->last_event = NULL;
 			continue;
 		}
 		s = &ei->section[ei->num_eit_sections - 1];
 		/* BUG: it's incorrect when last section has no event */
-		if(0 == s->num_events) {
+		if (0 == s->num_events) {
 			channel->last_event = NULL;
 			continue;
 		}
@@ -841,12 +760,11 @@ static int parse_mgt(int dmxfd)
 	int i, j, ret;
 
 	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&mgt);
-	if(0 > ret) {
-		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
-			__FUNCTION__);
+	if (0 > ret) {
+		fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
 		return -1;
 	}
-	if(0 == ret) {
+	if (0 == ret) {
 		fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
 		return 0;
 	}
@@ -855,31 +773,28 @@ static int parse_mgt(int dmxfd)
 	atsc_mgt_section_tables_for_each(mgt, t, i) {
 		struct mgt_table_name table;
 
-	for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
-		sizeof(struct mgt_table_name)); j++) {
-		if(t->table_type > mgt_tab_name_array[j].range) {
-			continue;
-		}
-		table = mgt_tab_name_array[j];
-		if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
-			mgt_tab_name_array[j].range) {
-			j = -1;
-		} else {
-			j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
-			if(0x017F == table.range) {
-				guide.eit_pid[j] = t->table_type_PID;
-			} else if (0x027F == table.range) {
-				guide.ett_pid[j] = t->table_type_PID;
+		for (j = 0; j < (int)(sizeof(mgt_tab_name_array) / sizeof(struct mgt_table_name)); j++) {
+			if (t->table_type > mgt_tab_name_array[j].range)
+				continue;
+			table = mgt_tab_name_array[j];
+			if (0 == j || mgt_tab_name_array[j - 1].range + 1 ==
+				mgt_tab_name_array[j].range) {
+				j = -1;
+			} else {
+				j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
+				if (0x017F == table.range) {
+					guide.eit_pid[j] = t->table_type_PID;
+				} else if (0x027F == table.range) {
+					guide.ett_pid[j] = t->table_type_PID;
+				}
 			}
+			break;
 		}
-		break;
-	}
 
 		fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X, %s", i,
-		    t->table_type, t->table_type_PID, table.string);
-		if(-1 != j) {
-		    fprintf(stdout, " %d", j);
-		}
+			t->table_type, t->table_type_PID, table.string);
+		if (-1 != j)
+			fprintf(stdout, " %d", j);
 		fprintf(stdout, "\n");
 	}
 
@@ -890,32 +805,24 @@ static int cleanup_guide(void)
 {
 	int i, j, k;
 
-	for(i = 0; i < guide.num_channels; i++) {
+	for (i = 0; i < guide.num_channels; i++) {
 		struct atsc_channel_info *channel = &guide.ch[i];
 
-		if(channel->title_buf.string) {
+		if (channel->title_buf.string)
 			free(channel->title_buf.string);
-		}
-		if(channel->msg_buf.string) {
+		if (channel->msg_buf.string)
 			free(channel->msg_buf.string);
-		}
-		for(j = 0; j < channel->num_eits; j++) {
+		for (j = 0; j < channel->num_eits; j++) {
 			struct atsc_eit_info *eit = &channel->eit[j];
 
-			for(k = 0; k < eit->num_eit_sections; k++) {
-				struct atsc_eit_section_info *section =
-					&eit->section[k];
-				if(section->num_events) {
+			for (k = 0; k < eit->num_eit_sections; k++) {
+				struct atsc_eit_section_info *section = &eit->section[k];
+				if (section->num_events)
 					free(section->events);
-				}
-			}
-			if(k) {
-				free(eit->section);
 			}
+			if (k) free(eit->section);
 		}
-		if(j) {
-			free(channel->eit);
-		}
+		if (j) free(channel->eit);
 	}
 
 	return 0;
@@ -927,38 +834,33 @@ static int print_events(struct atsc_chan
 	int m;
 	char line[256];
 
-	if(NULL == section) {
+	if (NULL == section) {
 		fprintf(stderr, "%s(): NULL pointer detected", __FUNCTION__);
 		return -1;
 	}
-	for(m = 0; m < section->num_events; m++) {
+	for (m = 0; m < section->num_events; m++) {
 		struct atsc_event_info *event =
 			section->events[m];
 
-		if(NULL == event) {
+		if (NULL == event)
 			continue;
-		}
-		fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
-			event->start.tm_hour, event->start.tm_min,
-			event->end.tm_hour, event->end.tm_min);
-		snprintf(line, event->title_len, "%s",
-			&channel->title_buf.string[event->title_pos]);
-		line[event->title_len] = '\0';
+		fprintf(stdout, "|%02d:%02d--%02d:%02d| ", event->start.tm_hour, event->start.tm_min, event->end.tm_hour, event->end.tm_min);
+		snprintf(line, event->title_len + 1, "%s", &channel->title_buf.string[event->title_pos]);
+		/*line[event->title_len] = '\0';*/
 		fprintf(stdout, "%s\n", line);
-		if(event->msg_len) {
+		if (event->msg_len) {
 			int len = event->msg_len;
 			int pos = event->msg_pos;
 			size_t part;
 
 			do {
 				part = len > 255 ? 255 : len;
-				snprintf(line, part, "%s",
-					&channel->msg_buf.string[pos]);
-				line[part] = '\0';
+				snprintf(line, part + 1, "%s", &channel->msg_buf.string[pos]);
+				/*line[part] = '\0';*/
 				fprintf(stdout, "%s", line);
 				len -= part;
 				pos += part;
-			} while(0 < len);
+			} while (0 < len);
 			fprintf(stdout, "\n");
 		}
 	}
@@ -970,20 +872,17 @@ static int print_guide(void)
 	int i, j, k;
 
 	fprintf(stdout, "%s\n", separator);
-	for(i = 0; i < guide.num_channels; i++) {
+	for (i = 0; i < guide.num_channels; i++) {
 		struct atsc_channel_info *channel = &guide.ch[i];
 
-		fprintf(stdout, "%d.%d  %s\n", channel->major_num,
-			channel->minor_num, channel->short_name);
-		for(j = 0; j < channel->num_eits; j++) {
+		fprintf(stdout, "%d.%d  %s\n", channel->major_num, channel->minor_num, channel->short_name);
+		for (j = 0; j < channel->num_eits; j++) {
 			struct atsc_eit_info *eit = &channel->eit[j];
 
-			for(k = 0; k < eit->num_eit_sections; k++) {
-				struct atsc_eit_section_info *section =
-					&eit->section[k];
-				if(print_events(channel, section)) {
-					fprintf(stderr, "%s(): error calling "
-						"print_events()\n", __FUNCTION__);
+			for (k = 0; k < eit->num_eit_sections; k++) {
+				struct atsc_eit_section_info *section = &eit->section[k];
+				if (print_events(channel, section)) {
+					fprintf(stderr, "%s(): error calling print_events()\n", __FUNCTION__);
 					return -1;
 				}
 			}
@@ -996,9 +895,8 @@ static int print_guide(void)
 
 static int open_demux(int *dmxfd)
 {
-	if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
-		fprintf(stderr, "%s(): error calling dvbdemux_open_demux()\n",
-			__FUNCTION__);
+	if ((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
+		fprintf(stderr, "%s(): error calling dvbdemux_open_demux()\n", __FUNCTION__);
 		return -1;
 	}
 	return 0;
@@ -1006,9 +904,8 @@ static int open_demux(int *dmxfd)
 
 static int close_demux(int dmxfd)
 {
-	if(dvbdemux_stop(dmxfd)) {
-		fprintf(stderr, "%s(): error calling dvbdemux_stop()\n",
-			__FUNCTION__);
+	if (dvbdemux_stop(dmxfd)) {
+		fprintf(stderr, "%s(): error calling dvbdemux_stop()\n", __FUNCTION__);
 		return -1;
 	}
 	return 0;
@@ -1033,60 +930,52 @@ static int atsc_scan_table(int dmxfd, ui
 	memset(mask, 0, sizeof(mask));
 	filter[0] = tag;
 	mask[0] = 0xFF;
-	if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
-		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
-			__FUNCTION__);
+	if (dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
+		fprintf(stderr, "%s(): error calling atsc_scan_table()\n", __FUNCTION__);
 		return -1;
 	}
 
 	/* poll for data */
 	pollfd.fd = dmxfd;
 	pollfd.events = POLLIN | POLLERR |POLLPRI;
-	if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
-		if(ctrl_c) {
+	if ((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
+		if (ctrl_c)
 			return 0;
-		}
 		fprintf(stderr, "%s(): error calling poll()\n", __FUNCTION__);
 		return -1;
 	}
 
-	if(0 == ret) {
+	if (0 == ret)
 		return 0;
-	}
 
 	/* read it */
-	if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
+	if ((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
 		fprintf(stderr, "%s(): error calling read()\n", __FUNCTION__);
 		return -1;
 	}
 
 	/* parse section */
 	section = section_codec(sibuf, size);
-	if(NULL == section) {
-		fprintf(stderr, "%s(): error calling section_codec()\n",
-			__FUNCTION__);
+	if (NULL == section) {
+		fprintf(stderr, "%s(): error calling section_codec()\n", __FUNCTION__);
 		return -1;
 	}
 
 	section_ext = section_ext_decode(section, 0);
-	if(NULL == section_ext) {
-		fprintf(stderr, "%s(): error calling section_ext_decode()\n",
-			__FUNCTION__);
+	if (NULL == section_ext) {
+		fprintf(stderr, "%s(): error calling section_ext_decode()\n", __FUNCTION__);
 		return -1;
 	}
 
 	psip = atsc_section_psip_decode(section_ext);
-	if(NULL == psip) {
-		fprintf(stderr,
-			"%s(): error calling atsc_section_psip_decode()\n",
-			__FUNCTION__);
+	if (NULL == psip) {
+		fprintf(stderr, "%s(): error calling atsc_section_psip_decode()\n", __FUNCTION__);
 		return -1;
 	}
 
 	*table_section = table_callback[tag & 0x0F](psip);
-	if(NULL == *table_section) {
-		fprintf(stderr, "%s(): error decode table section\n",
-			__FUNCTION__);
+	if (NULL == *table_section) {
+		fprintf(stderr, "%s(): error decode table section\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -1100,17 +989,16 @@ int main(int argc, char *argv[])
 
 	program = argv[0];
 
-	if(1 == argc) {
+	if (1 == argc) {
 		usage();
 		exit(-1);
 	}
 
-	for( ; ; ) {
+	for ( ; ; ) {
 		char c;
 
-		if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
+		if (-1 == (c = getopt(argc, argv, "a:f:p:m:th")))
 			break;
-		}
 
 		switch(c) {
 		case 'a':
@@ -1124,9 +1012,8 @@ int main(int argc, char *argv[])
 		case 'p':
 			period = strtol(optarg, NULL, 0);
 			/* each table covers 3 hours */
-			if((3 * MAX_NUM_EVENT_TABLES) < period) {
+			if ((3 * MAX_NUM_EVENT_TABLES) < period)
 				period = 3 * MAX_NUM_EVENT_TABLES;
-			}
 			break;
 
 		case 'm':
@@ -1154,94 +1041,81 @@ int main(int argc, char *argv[])
 	memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
 	memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
 
-	if(open_frontend(&fe)) {
-		fprintf(stderr, "%s(): error calling open_frontend()\n",
-			__FUNCTION__);
+	if (open_frontend(&fe)) {
+		fprintf(stderr, "%s(): error calling open_frontend()\n", __FUNCTION__);
 		return -1;
 	}
 
-	if(open_demux(&dmxfd)) {
-		fprintf(stderr, "%s(): error calling open_demux()\n",
-			__FUNCTION__);
+	if (open_demux(&dmxfd)) {
+		fprintf(stderr, "%s(): error calling open_demux()\n", __FUNCTION__);
 		return -1;
 	}
 
-	if(parse_stt(dmxfd)) {
-		fprintf(stderr, "%s(): error calling parse_stt()\n",
-			__FUNCTION__);
+	if (parse_stt(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_stt()\n", __FUNCTION__);
 		return -1;
 	}
 
-	if(parse_mgt(dmxfd)) {
-		fprintf(stderr, "%s(): error calling parse_mgt()\n",
-			__FUNCTION__);
+	if (parse_mgt(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_mgt()\n", __FUNCTION__);
 		return -1;
 	}
 
-	if(parse_tvct(dmxfd)) {
-		fprintf(stderr, "%s(): error calling parse_tvct()\n",
-			__FUNCTION__);
+	if (parse_tvct(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_tvct()\n", __FUNCTION__);
 		return -1;
 	}
 
 #ifdef ENABLE_RRT
-	if(parse_rrt(dmxfd)) {
-		fprintf(stderr, "%s(): error calling parse_rrt()\n",
-			__FUNCTION__);
+	if (parse_rrt(dmxfd)) {
+		fprintf(stderr, "%s(): error calling parse_rrt()\n", __FUNCTION__);
 		return -1;
 	}
 #endif
 
 	fprintf(stdout, "receiving EIT ");
-	for(i = 0; i < guide.ch[0].num_eits; i++) {
-		if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
-			fprintf(stderr, "%s(): error calling parse_eit()\n",
-				__FUNCTION__);
+	for (i = 0; i < guide.ch[0].num_eits; i++) {
+		if (parse_eit(dmxfd, i, guide.eit_pid[i])) {
+			fprintf(stderr, "%s(): error calling parse_eit()\n", __FUNCTION__);
 			return -1;
 		}
 	}
 	fprintf(stdout, "\n");
 
 	old_handler = signal(SIGINT, int_handler);
-	if(enable_ett) {
+	if (enable_ett) {
 		fprintf(stdout, "receiving ETT ");
-		for(i = 0; i < guide.ch[0].num_eits; i++) {
-			if(0xFFFF != guide.ett_pid[i]) {
-				if(parse_ett(dmxfd, i, guide.ett_pid[i])) {
-					fprintf(stderr, "%s(): error calling "
-						"parse_eit()\n", __FUNCTION__);
+		for (i = 0; i < guide.ch[0].num_eits; i++) {
+			if (0xFFFF != guide.ett_pid[i]) {
+				if (parse_ett(dmxfd, i, guide.ett_pid[i])) {
+					fprintf(stderr, "%s(): error calling parse_eit()\n", __FUNCTION__);
 					return -1;
 				}
 			}
-			if(ctrl_c) {
+			if (ctrl_c)
 				break;
-			}
 		}
 		fprintf(stdout, "\n");
 	}
 	signal(SIGINT, old_handler);
 
-	if(print_guide()) {
-		fprintf(stderr, "%s(): error calling print_guide()\n",
-			__FUNCTION__);
+	if (print_guide()) {
+		fprintf(stderr, "%s(): error calling print_guide()\n", __FUNCTION__);
 		return -1;
 	}
 
-	if(cleanup_guide()) {
-		fprintf(stderr, "%s(): error calling cleanup_guide()\n",
-			__FUNCTION__);
+	if (cleanup_guide()) {
+		fprintf(stderr, "%s(): error calling cleanup_guide()\n", __FUNCTION__);
 		return -1;
 	}
 
-	if(close_demux(dmxfd)) {
-		fprintf(stderr, "%s(): error calling close_demux()\n",
-			__FUNCTION__);
+	if (close_demux(dmxfd)) {
+		fprintf(stderr, "%s(): error calling close_demux()\n", __FUNCTION__);
 		return -1;
 	}
 
-	if(close_frontend(fe)) {
-		fprintf(stderr, "%s(): error calling close_demux()\n",
-			__FUNCTION__);
+	if (close_frontend(fe)) {
+		fprintf(stderr, "%s(): error calling close_demux()\n", __FUNCTION__);
 		return -1;
 	}
 
diff -upr dvb-apps/util/scan/Makefile dvb-apps_local/util/scan/Makefile
--- dvb-apps/util/scan/Makefile	2009-06-20 11:54:20.423986549 -0500
+++ dvb-apps_local/util/scan/Makefile	2009-06-20 11:57:50.914924733 -0500
@@ -14,7 +14,7 @@ inst_bin = $(binaries)
 
 removing = atsc_psip_section.c atsc_psip_section.h
 
-CPPFLAGS += -DDATADIR=\"$(prefix)/share\"
+CPPFLAGS += -Wno-packed-bitfield_nocompat -D__KERNEL_STRCIT_NAMES -DDATADIR=\"$(prefix)/share\"
 
 .PHONY: all
 



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] dvb-apps: code cleanup and bug fix.
  2009-06-20 17:15               ` [Patch] dvb-apps: code cleanup and bug fix Yufei Yuan
@ 2009-06-20 17:31                 ` Yufei Yuan
  0 siblings, 0 replies; 22+ messages in thread
From: Yufei Yuan @ 2009-06-20 17:31 UTC (permalink / raw)
  To: Manu Abraham; +Cc: Linux Media Mailing List

The Makefile part of the last patch was not correct. Please use this one, sorry.

--- dvb-apps/util/scan/Makefile	2009-06-20 12:28:52.544986677 -0500
+++ dvb-apps_local/util/scan/Makefile	2009-06-20 12:27:08.597924784 -0500
@@ -14,7 +14,7 @@ inst_bin = $(binaries)
 
 removing = atsc_psip_section.c atsc_psip_section.h
 
-CPPFLAGS += -DDATADIR=\"$(prefix)/share\"
+CPPFLAGS += -Wno-packed-bitfield-compat -D__KERNEL_STRICT_NAMES -DDATADIR=\"$(prefix)/share\"
 
 .PHONY: all
 

On Sat, 2009-06-20 at 12:16 -0500, Yufei Yuan wrote:
> This patch is against dvb-apps 1281. Following is what has been done:
> 
> 1. atsc_epg bug fix: when ETM message gets longer than 256 characters, the last
> character was chopped, due to incorrect calling to snprintf().
> 2. atsc_epg code cleanup:
>   - white space added after keywords;
>   - hard wrap around column 80 removed;
>   - one-line conditional statement now w/o brackets.
> 3. scan Makefile workaround for building in gcc4.4/kernel 2.6.30 was not picked up in 1279, include again.
> 
> Regards,
> 
> Signed-off-by: Yufei Yuan <yfyuan@gmail.com>
> 



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-20  7:30             ` Manu Abraham
  2009-06-20 13:30               ` Yufei Yuan
  2009-06-20 17:15               ` [Patch] dvb-apps: code cleanup and bug fix Yufei Yuan
@ 2009-06-22 23:43               ` Yufei Yuan
  2009-06-23  0:52                 ` hermann pitton
  2 siblings, 1 reply; 22+ messages in thread
From: Yufei Yuan @ 2009-06-22 23:43 UTC (permalink / raw)
  To: Manu Abraham; +Cc: Linux Media Mailing List

I sent out a new patch yesterday under a different subject line, but it 
looks like it did not make through it. Is this list a moderated one?
 
Anyway, please ignore yesterday's patch if you have not had a chance to 
look at it. Please use this following patch, which is against 1283. It 
contains: 

1. atsc_epg bug fix: when ETM message gets longer than 256 characters, 
the last character was chopped, due to incorrect calling to snprintf(). 
2. atsc_epg code cleanup:
  - error report function re-factored.
  - white space added after keywords;
  - hard wrap around column 80 removed;
  - one-line conditional statement now w/o brackets.
3. scan Makefile workaround for building in gcc4.4/kernel 2.6.30 was not 
picked up yet, include again.

Regards,

Signed-off-by: Yufei Yuan <yfyuan@gmail.com>

diff -upr dvb-apps/util/atsc_epg/atsc_epg.c dvb-apps_local/util/atsc_epg/atsc_epg.c
--- dvb-apps/util/atsc_epg/atsc_epg.c	2009-06-22 12:13:04.136925772 -0500
+++ dvb-apps_local/util/atsc_epg/atsc_epg.c	2009-06-22 13:17:15.287986505 -0500
@@ -20,6 +20,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <unistd.h>
 #include <string.h>
 #include <time.h>
@@ -46,6 +47,18 @@
 #define MAX_NUM_CHANNELS		16
 #define MAX_NUM_EVENTS_PER_CHANNEL	(4 * 24 * 7)
 
+static inline void print_error(const char *s, const char *f, ...)
+{
+	va_list ap;
+
+	va_start(ap, f);
+	fprintf(stderr, "%s(): ", s);
+	vfprintf(stderr, f, ap);
+	fprintf(stderr, "\n");
+}
+
+#define error_msg(format, ...) print_error(__FUNCTION__, format, ## __VA_ARGS__)
+
 static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
 	void **table_section);
 
@@ -168,9 +181,8 @@ void *(*table_callback[16])(struct atsc_
 
 static void int_handler(int sig_num)
 {
-	if(SIGINT != sig_num) {
+	if (SIGINT != sig_num)
 		return;
-	}
 	ctrl_c = 1;
 }
 
@@ -219,8 +231,9 @@ static void help(void)
 
 static int close_frontend(struct dvbfe_handle *fe)
 {
-	if(NULL == fe) {
-		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+	if (NULL == fe) {
+		error_msg("NULL pointer detected");
+		return -1;
 	}
 
 	dvbfe_close(fe);
@@ -232,24 +245,21 @@ static int open_frontend(struct dvbfe_ha
 {
 	struct dvbfe_info fe_info;
 
-	if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
-		fprintf(stderr, "%s(): error calling dvbfe_open()\n",
-			__FUNCTION__);
+	if (NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
+		error_msg("error calling dvbfe_open()");
 		return -1;
 	}
 	dvbfe_get_info(*fe, 0, &fe_info, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
-	if(DVBFE_TYPE_ATSC != fe_info.type) {
-		fprintf(stderr, "%s(): only ATSC frontend supported currently\n",
-			__FUNCTION__);
+	if (DVBFE_TYPE_ATSC != fe_info.type) {
+		error_msg("only ATSC frontend supported currently");
 		return -1;
 	}
 	fe_info.feparams.frequency = frequency;
 	fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
 	fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
 	fprintf(stdout, "tuning to %d Hz, please wait...\n", frequency);
-	if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
-		fprintf(stderr, "%s(): cannot lock to %d Hz in %d seconds\n",
-			__FUNCTION__, frequency, TIMEOUT);
+	if (dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
+		error_msg("cannot lock to %d Hz in %d seconds", frequency, TIMEOUT);
 		return -1;
 	}
 	fprintf(stdout, "tuner locked.\n");
@@ -257,7 +267,7 @@ static int open_frontend(struct dvbfe_ha
 	return 0;
 }
 
-#if ENABLE_RRT
+#ifdef ENABLE_RRT
 /* this is untested as since this part of the library is broken */
 static int parse_rrt(int dmxfd)
 {
@@ -270,20 +280,18 @@ static int parse_rrt(int dmxfd)
 	i = 0;
 	fprintf(stdout, "waiting for RRT: ");
 	fflush(stdout);
-	while(i < RRT_TIMEOUT) {
+	while (i < RRT_TIMEOUT) {
 		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&rrt);
-		if(0 > ret) {
-			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
-				__FUNCTION__);
+		if (0 > ret) {
+			error_msg("error calling atsc_scan_table()");
 			return -1;
 		}
-		if(0 == ret) {
-			if(RRT_TIMEOUT > i) {
+		if (0 == ret) {
+			if (RRT_TIMEOUT > i) {
 				fprintf(stdout, ".");
 				fflush(stdout);
 			} else {
-				fprintf(stdout, "\nno RRT in %d seconds\n",
-					RRT_TIMEOUT);
+				fprintf(stdout, "\nno RRT in %d seconds\n", RRT_TIMEOUT);
 				return 0;
 			}
 			i += TIMEOUT;
@@ -301,14 +309,13 @@ static int parse_rrt(int dmxfd)
 		atsc_text_string_segments_for_each(atsc_str, seg, j) {
 			const char *c;
 			int k;
-			if(seg->mode < 0x3E) {
-				fprintf(stderr, "%s(): text mode of 0x%02X "
-					"not supported yet\n",
-					__FUNCTION__, seg->mode);
+
+			if (seg->mode < 0x3E) {
+				error_msg("text mode of 0x%02X not supported yet", seg->mode);
 				return -1;
 			}
 			c = (const char *)atsc_text_string_segment_bytes(seg);
-			for(k = 0; k < seg->number_bytes; k++) {
+			for (k = 0; k < seg->number_bytes; k++) {
 				fprintf(stdout, "%c", c[k]);
 			}
 		}
@@ -327,12 +334,11 @@ static int parse_stt(int dmxfd)
 	int ret;
 
 	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&stt);
-	if(0 > ret) {
-		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
-			__FUNCTION__);
+	if (0 > ret) {
+		error_msg("error calling atsc_scan_table()");
 		return -1;
 	}
-	if(0 == ret) {
+	if (0 == ret) {
 		fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
 		return 0;
 	}
@@ -360,99 +366,86 @@ static int parse_tvct(int dmxfd)
 
 	do {
 		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&tvct);
-		if(0 > ret) {
-			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
-			__FUNCTION__);
+		if (0 > ret) {
+			error_msg("error calling atsc_scan_table()");
 			return -1;
 		}
-		if(0 == ret) {
+		if (0 == ret) {
 			fprintf(stdout, "no TVCT in %d seconds\n", TIMEOUT);
 			return 0;
 		}
 
-		if(-1 == num_sections) {
+		if (-1 == num_sections) {
 			num_sections = 1 + tvct->head.ext_head.last_section_number;
-			if(32 < num_sections) {
-				fprintf(stderr, "%s(): no support yet for "
-					"tables having more than 32 sections\n",
-					__FUNCTION__);
+			if (32 < num_sections) {
+				error_msg("no support yet for tables having more than 32 sections");
 				return -1;
 			}
 		} else {
-			if(num_sections !=
+			if (num_sections !=
 				1 + tvct->head.ext_head.last_section_number) {
-				fprintf(stderr,
-					"%s(): last section number does not match\n",
-					__FUNCTION__);
+				error_msg("last section number does not match");
 				return -1;
 			}
 		}
-		if(section_pattern & (1 << tvct->head.ext_head.section_number)) {
+		if (section_pattern & (1 << tvct->head.ext_head.section_number))
 			continue;
-		}
+
 		section_pattern |= 1 << tvct->head.ext_head.section_number;
 
-		if(MAX_NUM_CHANNELS < guide.num_channels +
+		if (MAX_NUM_CHANNELS < guide.num_channels +
 			tvct->num_channels_in_section) {
-			fprintf(stderr, "%s(): no support for more than %d "
-				"virtual channels in a pyhsical channel\n",
-				__FUNCTION__, MAX_NUM_CHANNELS);
+			error_msg("no support for more than %d virtual channels in a pyhsical channel", MAX_NUM_CHANNELS);
 			return -1;
 		}
 		curr_info = &guide.ch[guide.num_channels];
 		guide.num_channels += tvct->num_channels_in_section;
 
-	atsc_tvct_section_channels_for_each(tvct, ch, i) {
-		/* initialize the curr_info structure */
-		/* each EIT covers 3 hours */
-		curr_info->num_eits = (period / 3) + !!(period % 3);
-		while (curr_info->num_eits &&
-			(0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
-			curr_info->num_eits -= 1;
-		}
-		if(curr_info->eit) {
-			fprintf(stderr, "%s(): non-NULL pointer detected "
-				"during initialization", __FUNCTION__);
-			return -1;
-		}
-		if(NULL == (curr_info->eit = calloc(curr_info->num_eits,
-			sizeof(struct atsc_eit_info)))) {
-			fprintf(stderr, "%s(): error calling calloc()\n",
-				__FUNCTION__);
-			return -1;
-		}
-		if(NULL == (curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN,
-			sizeof(char)))) {
-			fprintf(stderr, "%s(): error calling calloc()\n",
-				__FUNCTION__);
-			return -1;
-		}
-		curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
-		curr_info->title_buf.buf_pos = 0;
+		atsc_tvct_section_channels_for_each(tvct, ch, i) {
+			/* initialize the curr_info structure */
+			/* each EIT covers 3 hours */
+			curr_info->num_eits = (period / 3) + !!(period % 3);
+			while (curr_info->num_eits &&
+				(0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
+				curr_info->num_eits -= 1;
+			}
+			if (curr_info->eit) {
+				error_msg("non-NULL pointer detected during initialization");
+				return -1;
+			}
+			curr_info->eit = calloc(curr_info->num_eits, sizeof(struct atsc_eit_info));
+			if (NULL == curr_info->eit) {
+				error_msg("error calling calloc()");
+				return -1;
+			}
+			curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN, sizeof(char));
+			if (NULL == curr_info->title_buf.string) {
+				error_msg("error calling calloc()");
+				return -1;
+			}
+			curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
+			curr_info->title_buf.buf_pos = 0;
 
-		if(NULL == (curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN,
-			sizeof(char)))) {
-			fprintf(stderr, "%s(): error calling calloc()\n",
-				__FUNCTION__);
-			return -1;
-		}
-		curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
-		curr_info->msg_buf.buf_pos = 0;
+			curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN, sizeof(char));
+			if (NULL == curr_info->msg_buf.string) {
+				error_msg("error calling calloc()");
+				return -1;
+			}
+			curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
+			curr_info->msg_buf.buf_pos = 0;
 
-		for(k = 0; k < 7; k++) {
-			curr_info->short_name[k] =
-				get_bits((const uint8_t *)ch->short_name,
-				k * 16, 16);
-		}
-		curr_info->service_type = ch->service_type;
-		curr_info->major_num = ch->major_channel_number;
-		curr_info->minor_num = ch->minor_channel_number;
-		curr_info->tsid = ch->channel_TSID;
-		curr_info->prog_num = ch->program_number;
-		curr_info->src_id = ch->source_id;
-		curr_info++;
+			for (k = 0; k < 7; k++)
+				curr_info->short_name[k] =
+					get_bits((const uint8_t *)ch->short_name, k * 16, 16);
+			curr_info->service_type = ch->service_type;
+			curr_info->major_num = ch->major_channel_number;
+			curr_info->minor_num = ch->minor_channel_number;
+			curr_info->tsid = ch->channel_TSID;
+			curr_info->prog_num = ch->program_number;
+			curr_info->src_id = ch->source_id;
+			curr_info++;
 		}
-	} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
+	} while (section_pattern != (uint32_t)((1 << num_sections) - 1));
 
 	return 0;
 }
@@ -463,22 +456,21 @@ static int match_event(struct atsc_eit_i
 	int j, k;
 	struct atsc_eit_section_info *section;
 
-	if(NULL == eit || NULL == event || NULL == curr_index) {
-		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+	if (NULL == eit || NULL == event || NULL == curr_index) {
+		error_msg("NULL pointer detected");
 		return -1;
 	}
 
-	for(j = 0; j < eit->num_eit_sections; j++) {
+	for (j = 0; j < eit->num_eit_sections; j++) {
 		section = &eit->section[j];
 
-		for(k = 0; k < section->num_events; k++) {
-			if(section->events[k] && section->events[k]->id ==
-				event_id) {
+		for (k = 0; k < section->num_events; k++) {
+			if (section->events[k] && section->events[k]->id == event_id) {
 				*event = section->events[k];
 				break;
 			}
 		}
-		if(*event) {
+		if (*event) {
 			*curr_index = j;
 			break;
 		}
@@ -494,8 +486,8 @@ static int parse_message(struct atsc_cha
 	struct atsc_text *text;
 	struct atsc_text_string *str;
 
-	if(NULL == ett || NULL == event || NULL == channel) {
-		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+	if (NULL == ett || NULL == event || NULL == channel) {
+		error_msg("NULL pointer detected");
 		return -1;
 	}
 
@@ -505,17 +497,11 @@ static int parse_message(struct atsc_cha
 
 		atsc_text_string_segments_for_each(str, seg, j) {
 			event->msg_pos = channel->msg_buf.buf_pos;
-			if(0 > atsc_text_segment_decode(seg,
-				(uint8_t **)&channel->msg_buf.string,
-				(size_t *)&channel->msg_buf.buf_len,
-				(size_t *)&channel->msg_buf.buf_pos)) {
-				fprintf(stderr, "%s(): error calling "
-					"atsc_text_segment_decode()\n",
-					__FUNCTION__);
+			if (0 > atsc_text_segment_decode(seg, (uint8_t **)&channel->msg_buf.string, (size_t *)&channel->msg_buf.buf_len, (size_t *)&channel->msg_buf.buf_pos)) {
+				error_msg("error calling atsc_text_segment_decode()");
 				return -1;
 			}
-			event->msg_len = 1 + channel->msg_buf.buf_pos -
-				event->msg_pos;
+			event->msg_len = channel->msg_buf.buf_pos - event->msg_pos;
 		}
 	}
 
@@ -535,69 +521,58 @@ static int parse_ett(int dmxfd, int inde
 	uint16_t source_id, event_id;
 	int c, ret;
 
-	if(0xFFFF == guide.ett_pid[index]) {
+	if (0xFFFF == guide.ett_pid[index])
 		return 0;
-	}
 
-	for(c = 0; c < guide.num_channels; c++) {
+	for (c = 0; c < guide.num_channels; c++) {
 		channel = &guide.ch[c];
 		eit = &channel->eit[index];
 
 		section_pattern = 0;
-		while(section_pattern !=
-			(uint32_t)((1 << eit->num_eit_sections) - 1)) {
-			if(ctrl_c) {
+		while (section_pattern != (uint32_t)((1 << eit->num_eit_sections) - 1)) {
+			if (ctrl_c)
 				return 0;
-			}
+
 			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&ett);
 			fprintf(stdout, ".");
 			fflush(stdout);
-			if(0 > ret) {
-				fprintf(stderr, "%s(): error calling "
-					"atsc_scan_table()\n", __FUNCTION__);
+			if (0 > ret) {
+				error_msg("error calling atsc_scan_table()");
 				return -1;
 			}
-			if(0 == ret) {
-				fprintf(stdout, "no ETT %d in %d seconds\n",
-					index, TIMEOUT);
+			if (0 == ret) {
+				fprintf(stdout, "no ETT %d in %d seconds\n", index, TIMEOUT);
 				return 0;
 			}
 
 			source_id = ett->ETM_source_id;
 			event_id = ett->ETM_sub_id;
-			if(source_id != channel->src_id) {
+			if (source_id != channel->src_id)
 				continue;
-			}
 
 			event = NULL;
-			if(match_event(eit, event_id, &event, &curr_index)) {
-				fprintf(stderr, "%s(): error calling "
-					"match_event()\n", __FUNCTION__);
+			if (match_event(eit, event_id, &event, &curr_index)) {
+				error_msg("error calling match_event()");
 				return -1;
 			}
-			if(NULL == event) {
+			if (NULL == event)
 				continue;
-			}
-			if(section_pattern & (1 << curr_index)) {
-				/* the section has been filled, so skip,
-				 * not consider version yet
-				 */
+
+			/* the section has been filled, so skip, not consider version yet */
+			if (section_pattern & (1 << curr_index))
 				continue;
-			}
-			if(event->msg_len) {
-				/* the message has been filled */
+
+			/* the message has been filled */
+			if (event->msg_len)
 				continue;
-			}
 
-			if(parse_message(channel, ett, event)) {
-				fprintf(stderr, "%s(): error calling "
-					"parse_message()\n", __FUNCTION__);
+			if (parse_message(channel, ett, event)) {
+				error_msg("error calling parse_message()");
 				return -1;
 			}
 			section = &eit->section[curr_index];
-			if(++section->num_received_etms == section->num_etms) {
+			if (++section->num_received_etms == section->num_etms)
 				section_pattern |= 1 << curr_index;
-			}
 		}
 	}
 
@@ -611,23 +586,20 @@ static int parse_events(struct atsc_chan
 	struct atsc_eit_event *e;
 	time_t start_time, end_time;
 
-	if(NULL == curr_info || NULL == eit) {
-		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
+	if (NULL == curr_info || NULL == eit) {
+		error_msg("NULL pointer detected");
 		return -1;
 	}
 
 	atsc_eit_section_events_for_each(eit, e, i) {
 		struct atsc_text *title;
 		struct atsc_text_string *str;
-		struct atsc_event_info *e_info =
-			&curr_info->e[curr_info->event_info_index];
+		struct atsc_event_info *e_info = &curr_info->e[curr_info->event_info_index];
 
-		if(0 == i && curr_info->last_event) {
-			if(e->event_id == curr_info->last_event->id) {
+		if (0 == i && curr_info->last_event) {
+			if (e->event_id == curr_info->last_event->id) {
 				section->events[i] = NULL;
-				/* skip if it's the same event spanning
-				 * over sections
-				 */
+				/* skip if it's the same event spanning over sections */
 				continue;
 			}
 		}
@@ -638,10 +610,9 @@ static int parse_events(struct atsc_chan
 		end_time = start_time + e->length_in_seconds;
 		localtime_r(&start_time, &e_info->start);
 		localtime_r(&end_time, &e_info->end);
-		if(0 != e->ETM_location && 3 != e->ETM_location) {
-			/* FIXME assume 1 and 2 is interchangable as of now */
+		/* FIXME assume 1 and 2 is interchangable as of now */
+		if (0 != e->ETM_location && 3 != e->ETM_location)
 			section->num_etms++;
-		}
 
 		title = atsc_eit_event_name_title_text(e);
 		atsc_text_strings_for_each(title, str, j) {
@@ -649,17 +620,11 @@ static int parse_events(struct atsc_chan
 
 			atsc_text_string_segments_for_each(str, seg, k) {
 				e_info->title_pos = curr_info->title_buf.buf_pos;
-				if(0 > atsc_text_segment_decode(seg,
-					(uint8_t **)&curr_info->title_buf.string,
-					(size_t *)&curr_info->title_buf.buf_len,
-					(size_t *)&curr_info->title_buf.buf_pos)) {
-					fprintf(stderr, "%s(): error calling "
-						"atsc_text_segment_decode()\n",
-						__FUNCTION__);
+				if (0 > atsc_text_segment_decode(seg, (uint8_t **)&curr_info->title_buf.string, (size_t *)&curr_info->title_buf.buf_len, (size_t *)&curr_info->title_buf.buf_pos)) {
+					error_msg("error calling atsc_text_segment_decode()");
 					return -1;
 				}
-				e_info->title_len = curr_info->title_buf.buf_pos -
-					e_info->title_pos + 1;
+				e_info->title_len = curr_info->title_buf.buf_pos - e_info->title_pos;
 			}
 		}
 	}
@@ -682,8 +647,7 @@ static int parse_eit(int dmxfd, int inde
 	uint32_t eit_instance_pattern = 0;
 	int i, k, ret;
 
-	while(eit_instance_pattern !=
-		(uint32_t)((1 << guide.num_channels) - 1)) {
+	while (eit_instance_pattern != (uint32_t)((1 << guide.num_channels) - 1)) {
 		source_id = 0xFFFF;
 		section_pattern = 0;
 		num_sections = -1;
@@ -692,102 +656,71 @@ static int parse_eit(int dmxfd, int inde
 			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&eit);
 			fprintf(stdout, ".");
 			fflush(stdout);
-			if(0 > ret) {
-				fprintf(stderr, "%s(): error calling "
-					"atsc_scan_table()\n", __FUNCTION__);
+			if (0 > ret) {
+				error_msg("error calling atsc_scan_table()");
 				return -1;
 			}
-			if(0 == ret) {
-				fprintf(stdout, "no EIT %d in %d seconds\n",
-					index, TIMEOUT);
+			if (0 == ret) {
+				fprintf(stdout, "no EIT %d in %d seconds\n", index, TIMEOUT);
 				return 0;
 			}
 
-			if(0xFFFF == source_id) {
+			if (0xFFFF == source_id) {
 			source_id = atsc_eit_section_source_id(eit);
-			for(k = 0; k < guide.num_channels; k++) {
-				if(source_id == guide.ch[k].src_id) {
+			for (k = 0; k < guide.num_channels; k++) {
+				if (source_id == guide.ch[k].src_id) {
 					curr_info = &guide.ch[k];
 					curr_channel_index = k;
-					if(0 == index) {
+					if (0 == index)
 						curr_info->last_event = NULL;
-					}
 					break;
 				}
 			}
-			if(k == guide.num_channels) {
-				fprintf(stderr, "%s(): cannot find source_id "
-					"0x%04X in the EIT\n",
-					__FUNCTION__, source_id);
+			if (k == guide.num_channels) {
+				error_msg("cannot find source_id 0x%04X in the EIT", source_id);
 				return -1;
 			}
 			} else {
-				if(source_id !=
-					atsc_eit_section_source_id(eit)) {
+				if (source_id != atsc_eit_section_source_id(eit))
 					continue;
-				}
 			}
-			if(eit_instance_pattern & (1 << curr_channel_index)) {
-				/* we have received this instance,
-				 * so quit quick
-				 */
+			/* if we have received this instance, quit quick */
+			if (eit_instance_pattern & (1 << curr_channel_index))
 				break;
-			}
 
-			if(-1 == num_sections) {
-				num_sections = 1 +
-					eit->head.ext_head.last_section_number;
-				if(32 < num_sections) {
-					fprintf(stderr,
-						"%s(): no support yet for "
-						"tables having more than "
-						"32 sections\n", __FUNCTION__);
+			if (-1 == num_sections) {
+				num_sections = 1 + eit->head.ext_head.last_section_number;
+				if (32 < num_sections) {
+					error_msg("no support yet for tables having more than 32 sections");
 					return -1;
 				}
 			} else {
-				if(num_sections != 1 +
-					eit->head.ext_head.last_section_number) {
-					fprintf(stderr,
-						"%s(): last section number "
-						"does not match\n",
-						__FUNCTION__);
+				if (num_sections != 1 + eit->head.ext_head.last_section_number) {
+					error_msg("last section number does not match");
 					return -1;
 				}
 			}
-			if(section_pattern &
-				(1 << eit->head.ext_head.section_number)) {
+			if (section_pattern & (1 << eit->head.ext_head.section_number))
 				continue;
-			}
 			section_pattern |= 1 << eit->head.ext_head.section_number;
 
 			eit_info = &curr_info->eit[index];
-			if(NULL == (eit_info->section =
-				realloc(eit_info->section,
-				(eit_info->num_eit_sections + 1) *
-				sizeof(struct atsc_eit_section_info)))) {
-				fprintf(stderr,
-					"%s(): error calling realloc()\n",
-					__FUNCTION__);
+			eit_info->section = realloc(eit_info->section, (eit_info->num_eit_sections + 1) * sizeof(struct atsc_eit_section_info));
+			if (NULL == eit_info->section) {
+				error_msg("error calling realloc()");
 				return -1;
 			}
 			section_num = eit->head.ext_head.section_number;
-			if(0 == eit_info->num_eit_sections) {
+			if (0 == eit_info->num_eit_sections) {
 				eit_info->num_eit_sections = 1;
 				section = eit_info->section;
 			} else {
-				/* have to sort it into section order
-				 * (temporal order)
-				 */
-				for(i = 0; i < eit_info->num_eit_sections; i++) {
-					if(eit_info->section[i].section_num >
-						section_num) {
+				/* have to sort it into section order (temporal order) */
+				for (i = 0; i < eit_info->num_eit_sections; i++) {
+					if (eit_info->section[i].section_num > section_num)
 						break;
-					}
 				}
-				memmove(&eit_info->section[i + 1],
-					&eit_info->section[i],
-					(eit_info->num_eit_sections - i) *
-					sizeof(struct atsc_eit_section_info));
+				memmove(&eit_info->section[i + 1], &eit_info->section[i], (eit_info->num_eit_sections - i) * sizeof(struct atsc_eit_section_info));
 				section = &eit_info->section[i - 1];
 				section = &eit_info->section[i];
 				eit_info->num_eit_sections += 1;
@@ -797,33 +730,31 @@ static int parse_eit(int dmxfd, int inde
 			section->num_events = eit->num_events_in_section;
 			section->num_etms = 0;
 			section->num_received_etms = 0;
-			if(NULL == (section->events = calloc(section->num_events,
-				sizeof(struct atsc_event_info *)))) {
-				fprintf(stderr, "%s(): error calling calloc()\n",
-					__FUNCTION__);
+			section->events = calloc(section->num_events, sizeof(struct atsc_event_info *));
+			if (NULL == section->events) {
+				error_msg("error calling calloc()");
 				return -1;
 			}
-			if(parse_events(curr_info, eit, section)) {
-				fprintf(stderr, "%s(): error calling "
-					"parse_events()\n", __FUNCTION__);
+			if (parse_events(curr_info, eit, section)) {
+				error_msg("error calling parse_events()");
 				return -1;
 			}
-		} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
+		} while (section_pattern != (uint32_t)((1 << num_sections) - 1));
 		eit_instance_pattern |= 1 << curr_channel_index;
 	}
 
-	for(i = 0; i < guide.num_channels; i++) {
+	for (i = 0; i < guide.num_channels; i++) {
 		struct atsc_channel_info *channel = &guide.ch[i];
 		struct atsc_eit_info *ei = &channel->eit[index];
 		struct atsc_eit_section_info *s;
 
-		if(0 == ei->num_eit_sections) {
+		if (0 == ei->num_eit_sections) {
 			channel->last_event = NULL;
 			continue;
 		}
 		s = &ei->section[ei->num_eit_sections - 1];
 		/* BUG: it's incorrect when last section has no event */
-		if(0 == s->num_events) {
+		if (0 == s->num_events) {
 			channel->last_event = NULL;
 			continue;
 		}
@@ -841,12 +772,11 @@ static int parse_mgt(int dmxfd)
 	int i, j, ret;
 
 	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&mgt);
-	if(0 > ret) {
-		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
-			__FUNCTION__);
+	if (0 > ret) {
+		error_msg("error calling atsc_scan_table()");
 		return -1;
 	}
-	if(0 == ret) {
+	if (0 == ret) {
 		fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
 		return 0;
 	}
@@ -855,31 +785,28 @@ static int parse_mgt(int dmxfd)
 	atsc_mgt_section_tables_for_each(mgt, t, i) {
 		struct mgt_table_name table;
 
-	for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
-		sizeof(struct mgt_table_name)); j++) {
-		if(t->table_type > mgt_tab_name_array[j].range) {
-			continue;
-		}
-		table = mgt_tab_name_array[j];
-		if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
-			mgt_tab_name_array[j].range) {
-			j = -1;
-		} else {
-			j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
-			if(0x017F == table.range) {
-				guide.eit_pid[j] = t->table_type_PID;
-			} else if (0x027F == table.range) {
-				guide.ett_pid[j] = t->table_type_PID;
+		for (j = 0; j < (int)(sizeof(mgt_tab_name_array) / sizeof(struct mgt_table_name)); j++) {
+			if (t->table_type > mgt_tab_name_array[j].range)
+				continue;
+			table = mgt_tab_name_array[j];
+			if (0 == j || mgt_tab_name_array[j - 1].range + 1 ==
+				mgt_tab_name_array[j].range) {
+				j = -1;
+			} else {
+				j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
+				if (0x017F == table.range) {
+					guide.eit_pid[j] = t->table_type_PID;
+				} else if (0x027F == table.range) {
+					guide.ett_pid[j] = t->table_type_PID;
+				}
 			}
+			break;
 		}
-		break;
-	}
 
 		fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X, %s", i,
-		    t->table_type, t->table_type_PID, table.string);
-		if(-1 != j) {
-		    fprintf(stdout, " %d", j);
-		}
+			t->table_type, t->table_type_PID, table.string);
+		if (-1 != j)
+			fprintf(stdout, " %d", j);
 		fprintf(stdout, "\n");
 	}
 
@@ -890,32 +817,24 @@ static int cleanup_guide(void)
 {
 	int i, j, k;
 
-	for(i = 0; i < guide.num_channels; i++) {
+	for (i = 0; i < guide.num_channels; i++) {
 		struct atsc_channel_info *channel = &guide.ch[i];
 
-		if(channel->title_buf.string) {
+		if (channel->title_buf.string)
 			free(channel->title_buf.string);
-		}
-		if(channel->msg_buf.string) {
+		if (channel->msg_buf.string)
 			free(channel->msg_buf.string);
-		}
-		for(j = 0; j < channel->num_eits; j++) {
+		for (j = 0; j < channel->num_eits; j++) {
 			struct atsc_eit_info *eit = &channel->eit[j];
 
-			for(k = 0; k < eit->num_eit_sections; k++) {
-				struct atsc_eit_section_info *section =
-					&eit->section[k];
-				if(section->num_events) {
+			for (k = 0; k < eit->num_eit_sections; k++) {
+				struct atsc_eit_section_info *section = &eit->section[k];
+				if (section->num_events)
 					free(section->events);
-				}
-			}
-			if(k) {
-				free(eit->section);
 			}
+			if (k) free(eit->section);
 		}
-		if(j) {
-			free(channel->eit);
-		}
+		if (j) free(channel->eit);
 	}
 
 	return 0;
@@ -927,38 +846,33 @@ static int print_events(struct atsc_chan
 	int m;
 	char line[256];
 
-	if(NULL == section) {
-		fprintf(stderr, "%s(): NULL pointer detected", __FUNCTION__);
+	if (NULL == section) {
+		error_msg("NULL pointer detected");
 		return -1;
 	}
-	for(m = 0; m < section->num_events; m++) {
+	for (m = 0; m < section->num_events; m++) {
 		struct atsc_event_info *event =
 			section->events[m];
 
-		if(NULL == event) {
+		if (NULL == event)
 			continue;
-		}
-		fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
-			event->start.tm_hour, event->start.tm_min,
-			event->end.tm_hour, event->end.tm_min);
-		snprintf(line, event->title_len, "%s",
-			&channel->title_buf.string[event->title_pos]);
-		line[event->title_len] = '\0';
+		fprintf(stdout, "|%02d:%02d--%02d:%02d| ", event->start.tm_hour, event->start.tm_min, event->end.tm_hour, event->end.tm_min);
+		snprintf(line, event->title_len + 1, "%s", &channel->title_buf.string[event->title_pos]);
+		/*line[event->title_len] = '\0';*/
 		fprintf(stdout, "%s\n", line);
-		if(event->msg_len) {
+		if (event->msg_len) {
 			int len = event->msg_len;
 			int pos = event->msg_pos;
 			size_t part;
 
 			do {
 				part = len > 255 ? 255 : len;
-				snprintf(line, part, "%s",
-					&channel->msg_buf.string[pos]);
-				line[part] = '\0';
+				snprintf(line, part + 1, "%s", &channel->msg_buf.string[pos]);
+				/*line[part] = '\0';*/
 				fprintf(stdout, "%s", line);
 				len -= part;
 				pos += part;
-			} while(0 < len);
+			} while (0 < len);
 			fprintf(stdout, "\n");
 		}
 	}
@@ -970,20 +884,17 @@ static int print_guide(void)
 	int i, j, k;
 
 	fprintf(stdout, "%s\n", separator);
-	for(i = 0; i < guide.num_channels; i++) {
+	for (i = 0; i < guide.num_channels; i++) {
 		struct atsc_channel_info *channel = &guide.ch[i];
 
-		fprintf(stdout, "%d.%d  %s\n", channel->major_num,
-			channel->minor_num, channel->short_name);
-		for(j = 0; j < channel->num_eits; j++) {
+		fprintf(stdout, "%d.%d  %s\n", channel->major_num, channel->minor_num, channel->short_name);
+		for (j = 0; j < channel->num_eits; j++) {
 			struct atsc_eit_info *eit = &channel->eit[j];
 
-			for(k = 0; k < eit->num_eit_sections; k++) {
-				struct atsc_eit_section_info *section =
-					&eit->section[k];
-				if(print_events(channel, section)) {
-					fprintf(stderr, "%s(): error calling "
-						"print_events()\n", __FUNCTION__);
+			for (k = 0; k < eit->num_eit_sections; k++) {
+				struct atsc_eit_section_info *section = &eit->section[k];
+				if (print_events(channel, section)) {
+					error_msg("error calling print_events()");
 					return -1;
 				}
 			}
@@ -996,9 +907,8 @@ static int print_guide(void)
 
 static int open_demux(int *dmxfd)
 {
-	if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
-		fprintf(stderr, "%s(): error calling dvbdemux_open_demux()\n",
-			__FUNCTION__);
+	if ((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
+		error_msg("error calling dvbdemux_open_demux()");
 		return -1;
 	}
 	return 0;
@@ -1006,9 +916,8 @@ static int open_demux(int *dmxfd)
 
 static int close_demux(int dmxfd)
 {
-	if(dvbdemux_stop(dmxfd)) {
-		fprintf(stderr, "%s(): error calling dvbdemux_stop()\n",
-			__FUNCTION__);
+	if (dvbdemux_stop(dmxfd)) {
+		error_msg("error calling dvbdemux_stop()");
 		return -1;
 	}
 	return 0;
@@ -1033,60 +942,52 @@ static int atsc_scan_table(int dmxfd, ui
 	memset(mask, 0, sizeof(mask));
 	filter[0] = tag;
 	mask[0] = 0xFF;
-	if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
-		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
-			__FUNCTION__);
+	if (dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
+		error_msg("error calling atsc_scan_table()");
 		return -1;
 	}
 
 	/* poll for data */
 	pollfd.fd = dmxfd;
 	pollfd.events = POLLIN | POLLERR |POLLPRI;
-	if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
-		if(ctrl_c) {
+	if ((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
+		if (ctrl_c)
 			return 0;
-		}
-		fprintf(stderr, "%s(): error calling poll()\n", __FUNCTION__);
+		error_msg("error calling poll()");
 		return -1;
 	}
 
-	if(0 == ret) {
+	if (0 == ret)
 		return 0;
-	}
 
 	/* read it */
-	if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
-		fprintf(stderr, "%s(): error calling read()\n", __FUNCTION__);
+	if ((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
+		error_msg("error calling read()");
 		return -1;
 	}
 
 	/* parse section */
 	section = section_codec(sibuf, size);
-	if(NULL == section) {
-		fprintf(stderr, "%s(): error calling section_codec()\n",
-			__FUNCTION__);
+	if (NULL == section) {
+		error_msg("error calling section_codec()");
 		return -1;
 	}
 
 	section_ext = section_ext_decode(section, 0);
-	if(NULL == section_ext) {
-		fprintf(stderr, "%s(): error calling section_ext_decode()\n",
-			__FUNCTION__);
+	if (NULL == section_ext) {
+		error_msg("error calling section_ext_decode()");
 		return -1;
 	}
 
 	psip = atsc_section_psip_decode(section_ext);
-	if(NULL == psip) {
-		fprintf(stderr,
-			"%s(): error calling atsc_section_psip_decode()\n",
-			__FUNCTION__);
+	if (NULL == psip) {
+		error_msg("error calling atsc_section_psip_decode()");
 		return -1;
 	}
 
 	*table_section = table_callback[tag & 0x0F](psip);
-	if(NULL == *table_section) {
-		fprintf(stderr, "%s(): error decode table section\n",
-			__FUNCTION__);
+	if (NULL == *table_section) {
+		error_msg("error decode table section");
 		return -1;
 	}
 
@@ -1100,17 +1001,16 @@ int main(int argc, char *argv[])
 
 	program = argv[0];
 
-	if(1 == argc) {
+	if (1 == argc) {
 		usage();
 		exit(-1);
 	}
 
-	for( ; ; ) {
+	for ( ; ; ) {
 		char c;
 
-		if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
+		if (-1 == (c = getopt(argc, argv, "a:f:p:m:th")))
 			break;
-		}
 
 		switch(c) {
 		case 'a':
@@ -1124,9 +1024,8 @@ int main(int argc, char *argv[])
 		case 'p':
 			period = strtol(optarg, NULL, 0);
 			/* each table covers 3 hours */
-			if((3 * MAX_NUM_EVENT_TABLES) < period) {
+			if ((3 * MAX_NUM_EVENT_TABLES) < period)
 				period = 3 * MAX_NUM_EVENT_TABLES;
-			}
 			break;
 
 		case 'm':
@@ -1154,94 +1053,81 @@ int main(int argc, char *argv[])
 	memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
 	memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
 
-	if(open_frontend(&fe)) {
-		fprintf(stderr, "%s(): error calling open_frontend()\n",
-			__FUNCTION__);
+	if (open_frontend(&fe)) {
+		error_msg("error calling open_frontend()");
 		return -1;
 	}
 
-	if(open_demux(&dmxfd)) {
-		fprintf(stderr, "%s(): error calling open_demux()\n",
-			__FUNCTION__);
+	if (open_demux(&dmxfd)) {
+		error_msg("error calling open_demux()");
 		return -1;
 	}
 
-	if(parse_stt(dmxfd)) {
-		fprintf(stderr, "%s(): error calling parse_stt()\n",
-			__FUNCTION__);
+	if (parse_stt(dmxfd)) {
+		error_msg("error calling parse_stt()");
 		return -1;
 	}
 
-	if(parse_mgt(dmxfd)) {
-		fprintf(stderr, "%s(): error calling parse_mgt()\n",
-			__FUNCTION__);
+	if (parse_mgt(dmxfd)) {
+		error_msg("error calling parse_mgt()");
 		return -1;
 	}
 
-	if(parse_tvct(dmxfd)) {
-		fprintf(stderr, "%s(): error calling parse_tvct()\n",
-			__FUNCTION__);
+	if (parse_tvct(dmxfd)) {
+		error_msg("error calling parse_tvct()");
 		return -1;
 	}
 
 #ifdef ENABLE_RRT
-	if(parse_rrt(dmxfd)) {
-		fprintf(stderr, "%s(): error calling parse_rrt()\n",
-			__FUNCTION__);
+	if (parse_rrt(dmxfd)) {
+		error_msg("error calling parse_rrt()");
 		return -1;
 	}
 #endif
 
 	fprintf(stdout, "receiving EIT ");
-	for(i = 0; i < guide.ch[0].num_eits; i++) {
-		if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
-			fprintf(stderr, "%s(): error calling parse_eit()\n",
-				__FUNCTION__);
+	for (i = 0; i < guide.ch[0].num_eits; i++) {
+		if (parse_eit(dmxfd, i, guide.eit_pid[i])) {
+			error_msg("error calling parse_eit()");
 			return -1;
 		}
 	}
 	fprintf(stdout, "\n");
 
 	old_handler = signal(SIGINT, int_handler);
-	if(enable_ett) {
+	if (enable_ett) {
 		fprintf(stdout, "receiving ETT ");
-		for(i = 0; i < guide.ch[0].num_eits; i++) {
-			if(0xFFFF != guide.ett_pid[i]) {
-				if(parse_ett(dmxfd, i, guide.ett_pid[i])) {
-					fprintf(stderr, "%s(): error calling "
-						"parse_eit()\n", __FUNCTION__);
+		for (i = 0; i < guide.ch[0].num_eits; i++) {
+			if (0xFFFF != guide.ett_pid[i]) {
+				if (parse_ett(dmxfd, i, guide.ett_pid[i])) {
+					error_msg("error calling parse_eit()");
 					return -1;
 				}
 			}
-			if(ctrl_c) {
+			if (ctrl_c)
 				break;
-			}
 		}
 		fprintf(stdout, "\n");
 	}
 	signal(SIGINT, old_handler);
 
-	if(print_guide()) {
-		fprintf(stderr, "%s(): error calling print_guide()\n",
-			__FUNCTION__);
+	if (print_guide()) {
+		error_msg("error calling print_guide()");
 		return -1;
 	}
 
-	if(cleanup_guide()) {
-		fprintf(stderr, "%s(): error calling cleanup_guide()\n",
-			__FUNCTION__);
+	if (cleanup_guide()) {
+		error_msg("error calling cleanup_guide()");
 		return -1;
 	}
 
-	if(close_demux(dmxfd)) {
-		fprintf(stderr, "%s(): error calling close_demux()\n",
-			__FUNCTION__);
+	if (close_demux(dmxfd)) {
+		error_msg("error calling close_demux()");
 		return -1;
 	}
 
-	if(close_frontend(fe)) {
-		fprintf(stderr, "%s(): error calling close_demux()\n",
-			__FUNCTION__);
+	if (close_frontend(fe)) {
+		error_msg("error calling close_demux()");
 		return -1;
 	}
 
diff -upr dvb-apps/util/scan/Makefile dvb-apps_local/util/scan/Makefile
--- dvb-apps/util/scan/Makefile	2009-06-22 12:13:04.171925478 -0500
+++ dvb-apps_local/util/scan/Makefile	2009-06-22 12:17:48.000000000 -0500
@@ -14,7 +14,7 @@ inst_bin = $(binaries)
 
 removing = atsc_psip_section.c atsc_psip_section.h
 
-CPPFLAGS += -DDATADIR=\"$(prefix)/share\"
+CPPFLAGS += -Wno-packed-bitfield-compat -D__KERNEL_STRICT_NAMES -DDATADIR=\"$(prefix)/share\"
 
 .PHONY: all
 



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Patch] New utility program atsc_epg added to dvb-apps utility suite.
  2009-06-22 23:43               ` [Patch] New utility program atsc_epg added to dvb-apps utility suite Yufei Yuan
@ 2009-06-23  0:52                 ` hermann pitton
  0 siblings, 0 replies; 22+ messages in thread
From: hermann pitton @ 2009-06-23  0:52 UTC (permalink / raw)
  To: yfyuan; +Cc: Manu Abraham, Linux Media Mailing List

Hi,

Am Montag, den 22.06.2009, 18:43 -0500 schrieb Yufei Yuan:
> I sent out a new patch yesterday under a different subject line, but it 
> looks like it did not make through it. Is this list a moderated one?
>  
> Anyway, please ignore yesterday's patch if you have not had a chance to 
> look at it. Please use this following patch, which is against 1283. It 
> contains: 

your patch from yesterday arrived, but the mirrors don't work reliable I
guess.

You are on the right list, but it is obviously not moderated enough, if
you look at what others also do with mail footers ;)

> _________________________________________________________________
> > Hotmail® has ever-growing storage! Don’t worry about storage limits.
> > http://windowslive.com/Tutorial/Hotmail/Storage?ocid=TXT_TAGLM_WL_HM_Tutorial_Storage_062009--
> > To unsubscribe from this list: send the line "unsubscribe linux-media" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> 
> _________________________________________________________________
> Bing™  brings you maps, menus, and reviews organized in one place.   Try it now.
> http://www.bing.com/search?q=restaurants&form=MLOGEN&publ=WLHMTAG&crea=TEXT_MLOGEN_Core_tagline_local_1x1--
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
Lauren found her dream laptop. Find the PC that’s right for you.
http://www.microsoft.com/windows/choosepc/?ocid=ftp_val_wl_290--
To unsubscribe from this list: send the line "unsubscribe linux-media"
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

:)

Cheers,
Hermann

> 1. atsc_epg bug fix: when ETM message gets longer than 256 characters, 
> the last character was chopped, due to incorrect calling to snprintf(). 
> 2. atsc_epg code cleanup:
>   - error report function re-factored.
>   - white space added after keywords;
>   - hard wrap around column 80 removed;
>   - one-line conditional statement now w/o brackets.
> 3. scan Makefile workaround for building in gcc4.4/kernel 2.6.30 was not 
> picked up yet, include again.
> 
> Regards,
> 
> Signed-off-by: Yufei Yuan <yfyuan@gmail.com>
> 
> diff -upr dvb-apps/util/atsc_epg/atsc_epg.c dvb-apps_local/util/atsc_epg/atsc_epg.c
> --- dvb-apps/util/atsc_epg/atsc_epg.c	2009-06-22 12:13:04.136925772 -0500
> +++ dvb-apps_local/util/atsc_epg/atsc_epg.c	2009-06-22 13:17:15.287986505 -0500
> @@ -20,6 +20,7 @@
>  
>  #include <stdio.h>
>  #include <stdlib.h>
> +#include <stdarg.h>
>  #include <unistd.h>
>  #include <string.h>
>  #include <time.h>
> @@ -46,6 +47,18 @@
>  #define MAX_NUM_CHANNELS		16
>  #define MAX_NUM_EVENTS_PER_CHANNEL	(4 * 24 * 7)
>  
> +static inline void print_error(const char *s, const char *f, ...)
> +{
> +	va_list ap;
> +
> +	va_start(ap, f);
> +	fprintf(stderr, "%s(): ", s);
> +	vfprintf(stderr, f, ap);
> +	fprintf(stderr, "\n");
> +}
> +
> +#define error_msg(format, ...) print_error(__FUNCTION__, format, ## __VA_ARGS__)
> +
>  static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
>  	void **table_section);
>  
> @@ -168,9 +181,8 @@ void *(*table_callback[16])(struct atsc_
>  
>  static void int_handler(int sig_num)
>  {
> -	if(SIGINT != sig_num) {
> +	if (SIGINT != sig_num)
>  		return;
> -	}
>  	ctrl_c = 1;
>  }
>  
> @@ -219,8 +231,9 @@ static void help(void)
>  
>  static int close_frontend(struct dvbfe_handle *fe)
>  {
> -	if(NULL == fe) {
> -		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +	if (NULL == fe) {
> +		error_msg("NULL pointer detected");
> +		return -1;
>  	}
>  
>  	dvbfe_close(fe);
> @@ -232,24 +245,21 @@ static int open_frontend(struct dvbfe_ha
>  {
>  	struct dvbfe_info fe_info;
>  
> -	if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
> -		fprintf(stderr, "%s(): error calling dvbfe_open()\n",
> -			__FUNCTION__);
> +	if (NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
> +		error_msg("error calling dvbfe_open()");
>  		return -1;
>  	}
>  	dvbfe_get_info(*fe, 0, &fe_info, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
> -	if(DVBFE_TYPE_ATSC != fe_info.type) {
> -		fprintf(stderr, "%s(): only ATSC frontend supported currently\n",
> -			__FUNCTION__);
> +	if (DVBFE_TYPE_ATSC != fe_info.type) {
> +		error_msg("only ATSC frontend supported currently");
>  		return -1;
>  	}
>  	fe_info.feparams.frequency = frequency;
>  	fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
>  	fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
>  	fprintf(stdout, "tuning to %d Hz, please wait...\n", frequency);
> -	if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
> -		fprintf(stderr, "%s(): cannot lock to %d Hz in %d seconds\n",
> -			__FUNCTION__, frequency, TIMEOUT);
> +	if (dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
> +		error_msg("cannot lock to %d Hz in %d seconds", frequency, TIMEOUT);
>  		return -1;
>  	}
>  	fprintf(stdout, "tuner locked.\n");
> @@ -257,7 +267,7 @@ static int open_frontend(struct dvbfe_ha
>  	return 0;
>  }
>  
> -#if ENABLE_RRT
> +#ifdef ENABLE_RRT
>  /* this is untested as since this part of the library is broken */
>  static int parse_rrt(int dmxfd)
>  {
> @@ -270,20 +280,18 @@ static int parse_rrt(int dmxfd)
>  	i = 0;
>  	fprintf(stdout, "waiting for RRT: ");
>  	fflush(stdout);
> -	while(i < RRT_TIMEOUT) {
> +	while (i < RRT_TIMEOUT) {
>  		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&rrt);
> -		if(0 > ret) {
> -			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> -				__FUNCTION__);
> +		if (0 > ret) {
> +			error_msg("error calling atsc_scan_table()");
>  			return -1;
>  		}
> -		if(0 == ret) {
> -			if(RRT_TIMEOUT > i) {
> +		if (0 == ret) {
> +			if (RRT_TIMEOUT > i) {
>  				fprintf(stdout, ".");
>  				fflush(stdout);
>  			} else {
> -				fprintf(stdout, "\nno RRT in %d seconds\n",
> -					RRT_TIMEOUT);
> +				fprintf(stdout, "\nno RRT in %d seconds\n", RRT_TIMEOUT);
>  				return 0;
>  			}
>  			i += TIMEOUT;
> @@ -301,14 +309,13 @@ static int parse_rrt(int dmxfd)
>  		atsc_text_string_segments_for_each(atsc_str, seg, j) {
>  			const char *c;
>  			int k;
> -			if(seg->mode < 0x3E) {
> -				fprintf(stderr, "%s(): text mode of 0x%02X "
> -					"not supported yet\n",
> -					__FUNCTION__, seg->mode);
> +
> +			if (seg->mode < 0x3E) {
> +				error_msg("text mode of 0x%02X not supported yet", seg->mode);
>  				return -1;
>  			}
>  			c = (const char *)atsc_text_string_segment_bytes(seg);
> -			for(k = 0; k < seg->number_bytes; k++) {
> +			for (k = 0; k < seg->number_bytes; k++) {
>  				fprintf(stdout, "%c", c[k]);
>  			}
>  		}
> @@ -327,12 +334,11 @@ static int parse_stt(int dmxfd)
>  	int ret;
>  
>  	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&stt);
> -	if(0 > ret) {
> -		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> -			__FUNCTION__);
> +	if (0 > ret) {
> +		error_msg("error calling atsc_scan_table()");
>  		return -1;
>  	}
> -	if(0 == ret) {
> +	if (0 == ret) {
>  		fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
>  		return 0;
>  	}
> @@ -360,99 +366,86 @@ static int parse_tvct(int dmxfd)
>  
>  	do {
>  		ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&tvct);
> -		if(0 > ret) {
> -			fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> -			__FUNCTION__);
> +		if (0 > ret) {
> +			error_msg("error calling atsc_scan_table()");
>  			return -1;
>  		}
> -		if(0 == ret) {
> +		if (0 == ret) {
>  			fprintf(stdout, "no TVCT in %d seconds\n", TIMEOUT);
>  			return 0;
>  		}
>  
> -		if(-1 == num_sections) {
> +		if (-1 == num_sections) {
>  			num_sections = 1 + tvct->head.ext_head.last_section_number;
> -			if(32 < num_sections) {
> -				fprintf(stderr, "%s(): no support yet for "
> -					"tables having more than 32 sections\n",
> -					__FUNCTION__);
> +			if (32 < num_sections) {
> +				error_msg("no support yet for tables having more than 32 sections");
>  				return -1;
>  			}
>  		} else {
> -			if(num_sections !=
> +			if (num_sections !=
>  				1 + tvct->head.ext_head.last_section_number) {
> -				fprintf(stderr,
> -					"%s(): last section number does not match\n",
> -					__FUNCTION__);
> +				error_msg("last section number does not match");
>  				return -1;
>  			}
>  		}
> -		if(section_pattern & (1 << tvct->head.ext_head.section_number)) {
> +		if (section_pattern & (1 << tvct->head.ext_head.section_number))
>  			continue;
> -		}
> +
>  		section_pattern |= 1 << tvct->head.ext_head.section_number;
>  
> -		if(MAX_NUM_CHANNELS < guide.num_channels +
> +		if (MAX_NUM_CHANNELS < guide.num_channels +
>  			tvct->num_channels_in_section) {
> -			fprintf(stderr, "%s(): no support for more than %d "
> -				"virtual channels in a pyhsical channel\n",
> -				__FUNCTION__, MAX_NUM_CHANNELS);
> +			error_msg("no support for more than %d virtual channels in a pyhsical channel", MAX_NUM_CHANNELS);
>  			return -1;
>  		}
>  		curr_info = &guide.ch[guide.num_channels];
>  		guide.num_channels += tvct->num_channels_in_section;
>  
> -	atsc_tvct_section_channels_for_each(tvct, ch, i) {
> -		/* initialize the curr_info structure */
> -		/* each EIT covers 3 hours */
> -		curr_info->num_eits = (period / 3) + !!(period % 3);
> -		while (curr_info->num_eits &&
> -			(0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
> -			curr_info->num_eits -= 1;
> -		}
> -		if(curr_info->eit) {
> -			fprintf(stderr, "%s(): non-NULL pointer detected "
> -				"during initialization", __FUNCTION__);
> -			return -1;
> -		}
> -		if(NULL == (curr_info->eit = calloc(curr_info->num_eits,
> -			sizeof(struct atsc_eit_info)))) {
> -			fprintf(stderr, "%s(): error calling calloc()\n",
> -				__FUNCTION__);
> -			return -1;
> -		}
> -		if(NULL == (curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN,
> -			sizeof(char)))) {
> -			fprintf(stderr, "%s(): error calling calloc()\n",
> -				__FUNCTION__);
> -			return -1;
> -		}
> -		curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
> -		curr_info->title_buf.buf_pos = 0;
> +		atsc_tvct_section_channels_for_each(tvct, ch, i) {
> +			/* initialize the curr_info structure */
> +			/* each EIT covers 3 hours */
> +			curr_info->num_eits = (period / 3) + !!(period % 3);
> +			while (curr_info->num_eits &&
> +				(0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
> +				curr_info->num_eits -= 1;
> +			}
> +			if (curr_info->eit) {
> +				error_msg("non-NULL pointer detected during initialization");
> +				return -1;
> +			}
> +			curr_info->eit = calloc(curr_info->num_eits, sizeof(struct atsc_eit_info));
> +			if (NULL == curr_info->eit) {
> +				error_msg("error calling calloc()");
> +				return -1;
> +			}
> +			curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN, sizeof(char));
> +			if (NULL == curr_info->title_buf.string) {
> +				error_msg("error calling calloc()");
> +				return -1;
> +			}
> +			curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
> +			curr_info->title_buf.buf_pos = 0;
>  
> -		if(NULL == (curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN,
> -			sizeof(char)))) {
> -			fprintf(stderr, "%s(): error calling calloc()\n",
> -				__FUNCTION__);
> -			return -1;
> -		}
> -		curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
> -		curr_info->msg_buf.buf_pos = 0;
> +			curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN, sizeof(char));
> +			if (NULL == curr_info->msg_buf.string) {
> +				error_msg("error calling calloc()");
> +				return -1;
> +			}
> +			curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
> +			curr_info->msg_buf.buf_pos = 0;
>  
> -		for(k = 0; k < 7; k++) {
> -			curr_info->short_name[k] =
> -				get_bits((const uint8_t *)ch->short_name,
> -				k * 16, 16);
> -		}
> -		curr_info->service_type = ch->service_type;
> -		curr_info->major_num = ch->major_channel_number;
> -		curr_info->minor_num = ch->minor_channel_number;
> -		curr_info->tsid = ch->channel_TSID;
> -		curr_info->prog_num = ch->program_number;
> -		curr_info->src_id = ch->source_id;
> -		curr_info++;
> +			for (k = 0; k < 7; k++)
> +				curr_info->short_name[k] =
> +					get_bits((const uint8_t *)ch->short_name, k * 16, 16);
> +			curr_info->service_type = ch->service_type;
> +			curr_info->major_num = ch->major_channel_number;
> +			curr_info->minor_num = ch->minor_channel_number;
> +			curr_info->tsid = ch->channel_TSID;
> +			curr_info->prog_num = ch->program_number;
> +			curr_info->src_id = ch->source_id;
> +			curr_info++;
>  		}
> -	} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
> +	} while (section_pattern != (uint32_t)((1 << num_sections) - 1));
>  
>  	return 0;
>  }
> @@ -463,22 +456,21 @@ static int match_event(struct atsc_eit_i
>  	int j, k;
>  	struct atsc_eit_section_info *section;
>  
> -	if(NULL == eit || NULL == event || NULL == curr_index) {
> -		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +	if (NULL == eit || NULL == event || NULL == curr_index) {
> +		error_msg("NULL pointer detected");
>  		return -1;
>  	}
>  
> -	for(j = 0; j < eit->num_eit_sections; j++) {
> +	for (j = 0; j < eit->num_eit_sections; j++) {
>  		section = &eit->section[j];
>  
> -		for(k = 0; k < section->num_events; k++) {
> -			if(section->events[k] && section->events[k]->id ==
> -				event_id) {
> +		for (k = 0; k < section->num_events; k++) {
> +			if (section->events[k] && section->events[k]->id == event_id) {
>  				*event = section->events[k];
>  				break;
>  			}
>  		}
> -		if(*event) {
> +		if (*event) {
>  			*curr_index = j;
>  			break;
>  		}
> @@ -494,8 +486,8 @@ static int parse_message(struct atsc_cha
>  	struct atsc_text *text;
>  	struct atsc_text_string *str;
>  
> -	if(NULL == ett || NULL == event || NULL == channel) {
> -		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +	if (NULL == ett || NULL == event || NULL == channel) {
> +		error_msg("NULL pointer detected");
>  		return -1;
>  	}
>  
> @@ -505,17 +497,11 @@ static int parse_message(struct atsc_cha
>  
>  		atsc_text_string_segments_for_each(str, seg, j) {
>  			event->msg_pos = channel->msg_buf.buf_pos;
> -			if(0 > atsc_text_segment_decode(seg,
> -				(uint8_t **)&channel->msg_buf.string,
> -				(size_t *)&channel->msg_buf.buf_len,
> -				(size_t *)&channel->msg_buf.buf_pos)) {
> -				fprintf(stderr, "%s(): error calling "
> -					"atsc_text_segment_decode()\n",
> -					__FUNCTION__);
> +			if (0 > atsc_text_segment_decode(seg, (uint8_t **)&channel->msg_buf.string, (size_t *)&channel->msg_buf.buf_len, (size_t *)&channel->msg_buf.buf_pos)) {
> +				error_msg("error calling atsc_text_segment_decode()");
>  				return -1;
>  			}
> -			event->msg_len = 1 + channel->msg_buf.buf_pos -
> -				event->msg_pos;
> +			event->msg_len = channel->msg_buf.buf_pos - event->msg_pos;
>  		}
>  	}
>  
> @@ -535,69 +521,58 @@ static int parse_ett(int dmxfd, int inde
>  	uint16_t source_id, event_id;
>  	int c, ret;
>  
> -	if(0xFFFF == guide.ett_pid[index]) {
> +	if (0xFFFF == guide.ett_pid[index])
>  		return 0;
> -	}
>  
> -	for(c = 0; c < guide.num_channels; c++) {
> +	for (c = 0; c < guide.num_channels; c++) {
>  		channel = &guide.ch[c];
>  		eit = &channel->eit[index];
>  
>  		section_pattern = 0;
> -		while(section_pattern !=
> -			(uint32_t)((1 << eit->num_eit_sections) - 1)) {
> -			if(ctrl_c) {
> +		while (section_pattern != (uint32_t)((1 << eit->num_eit_sections) - 1)) {
> +			if (ctrl_c)
>  				return 0;
> -			}
> +
>  			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&ett);
>  			fprintf(stdout, ".");
>  			fflush(stdout);
> -			if(0 > ret) {
> -				fprintf(stderr, "%s(): error calling "
> -					"atsc_scan_table()\n", __FUNCTION__);
> +			if (0 > ret) {
> +				error_msg("error calling atsc_scan_table()");
>  				return -1;
>  			}
> -			if(0 == ret) {
> -				fprintf(stdout, "no ETT %d in %d seconds\n",
> -					index, TIMEOUT);
> +			if (0 == ret) {
> +				fprintf(stdout, "no ETT %d in %d seconds\n", index, TIMEOUT);
>  				return 0;
>  			}
>  
>  			source_id = ett->ETM_source_id;
>  			event_id = ett->ETM_sub_id;
> -			if(source_id != channel->src_id) {
> +			if (source_id != channel->src_id)
>  				continue;
> -			}
>  
>  			event = NULL;
> -			if(match_event(eit, event_id, &event, &curr_index)) {
> -				fprintf(stderr, "%s(): error calling "
> -					"match_event()\n", __FUNCTION__);
> +			if (match_event(eit, event_id, &event, &curr_index)) {
> +				error_msg("error calling match_event()");
>  				return -1;
>  			}
> -			if(NULL == event) {
> +			if (NULL == event)
>  				continue;
> -			}
> -			if(section_pattern & (1 << curr_index)) {
> -				/* the section has been filled, so skip,
> -				 * not consider version yet
> -				 */
> +
> +			/* the section has been filled, so skip, not consider version yet */
> +			if (section_pattern & (1 << curr_index))
>  				continue;
> -			}
> -			if(event->msg_len) {
> -				/* the message has been filled */
> +
> +			/* the message has been filled */
> +			if (event->msg_len)
>  				continue;
> -			}
>  
> -			if(parse_message(channel, ett, event)) {
> -				fprintf(stderr, "%s(): error calling "
> -					"parse_message()\n", __FUNCTION__);
> +			if (parse_message(channel, ett, event)) {
> +				error_msg("error calling parse_message()");
>  				return -1;
>  			}
>  			section = &eit->section[curr_index];
> -			if(++section->num_received_etms == section->num_etms) {
> +			if (++section->num_received_etms == section->num_etms)
>  				section_pattern |= 1 << curr_index;
> -			}
>  		}
>  	}
>  
> @@ -611,23 +586,20 @@ static int parse_events(struct atsc_chan
>  	struct atsc_eit_event *e;
>  	time_t start_time, end_time;
>  
> -	if(NULL == curr_info || NULL == eit) {
> -		fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
> +	if (NULL == curr_info || NULL == eit) {
> +		error_msg("NULL pointer detected");
>  		return -1;
>  	}
>  
>  	atsc_eit_section_events_for_each(eit, e, i) {
>  		struct atsc_text *title;
>  		struct atsc_text_string *str;
> -		struct atsc_event_info *e_info =
> -			&curr_info->e[curr_info->event_info_index];
> +		struct atsc_event_info *e_info = &curr_info->e[curr_info->event_info_index];
>  
> -		if(0 == i && curr_info->last_event) {
> -			if(e->event_id == curr_info->last_event->id) {
> +		if (0 == i && curr_info->last_event) {
> +			if (e->event_id == curr_info->last_event->id) {
>  				section->events[i] = NULL;
> -				/* skip if it's the same event spanning
> -				 * over sections
> -				 */
> +				/* skip if it's the same event spanning over sections */
>  				continue;
>  			}
>  		}
> @@ -638,10 +610,9 @@ static int parse_events(struct atsc_chan
>  		end_time = start_time + e->length_in_seconds;
>  		localtime_r(&start_time, &e_info->start);
>  		localtime_r(&end_time, &e_info->end);
> -		if(0 != e->ETM_location && 3 != e->ETM_location) {
> -			/* FIXME assume 1 and 2 is interchangable as of now */
> +		/* FIXME assume 1 and 2 is interchangable as of now */
> +		if (0 != e->ETM_location && 3 != e->ETM_location)
>  			section->num_etms++;
> -		}
>  
>  		title = atsc_eit_event_name_title_text(e);
>  		atsc_text_strings_for_each(title, str, j) {
> @@ -649,17 +620,11 @@ static int parse_events(struct atsc_chan
>  
>  			atsc_text_string_segments_for_each(str, seg, k) {
>  				e_info->title_pos = curr_info->title_buf.buf_pos;
> -				if(0 > atsc_text_segment_decode(seg,
> -					(uint8_t **)&curr_info->title_buf.string,
> -					(size_t *)&curr_info->title_buf.buf_len,
> -					(size_t *)&curr_info->title_buf.buf_pos)) {
> -					fprintf(stderr, "%s(): error calling "
> -						"atsc_text_segment_decode()\n",
> -						__FUNCTION__);
> +				if (0 > atsc_text_segment_decode(seg, (uint8_t **)&curr_info->title_buf.string, (size_t *)&curr_info->title_buf.buf_len, (size_t *)&curr_info->title_buf.buf_pos)) {
> +					error_msg("error calling atsc_text_segment_decode()");
>  					return -1;
>  				}
> -				e_info->title_len = curr_info->title_buf.buf_pos -
> -					e_info->title_pos + 1;
> +				e_info->title_len = curr_info->title_buf.buf_pos - e_info->title_pos;
>  			}
>  		}
>  	}
> @@ -682,8 +647,7 @@ static int parse_eit(int dmxfd, int inde
>  	uint32_t eit_instance_pattern = 0;
>  	int i, k, ret;
>  
> -	while(eit_instance_pattern !=
> -		(uint32_t)((1 << guide.num_channels) - 1)) {
> +	while (eit_instance_pattern != (uint32_t)((1 << guide.num_channels) - 1)) {
>  		source_id = 0xFFFF;
>  		section_pattern = 0;
>  		num_sections = -1;
> @@ -692,102 +656,71 @@ static int parse_eit(int dmxfd, int inde
>  			ret = atsc_scan_table(dmxfd, pid, tag, (void **)&eit);
>  			fprintf(stdout, ".");
>  			fflush(stdout);
> -			if(0 > ret) {
> -				fprintf(stderr, "%s(): error calling "
> -					"atsc_scan_table()\n", __FUNCTION__);
> +			if (0 > ret) {
> +				error_msg("error calling atsc_scan_table()");
>  				return -1;
>  			}
> -			if(0 == ret) {
> -				fprintf(stdout, "no EIT %d in %d seconds\n",
> -					index, TIMEOUT);
> +			if (0 == ret) {
> +				fprintf(stdout, "no EIT %d in %d seconds\n", index, TIMEOUT);
>  				return 0;
>  			}
>  
> -			if(0xFFFF == source_id) {
> +			if (0xFFFF == source_id) {
>  			source_id = atsc_eit_section_source_id(eit);
> -			for(k = 0; k < guide.num_channels; k++) {
> -				if(source_id == guide.ch[k].src_id) {
> +			for (k = 0; k < guide.num_channels; k++) {
> +				if (source_id == guide.ch[k].src_id) {
>  					curr_info = &guide.ch[k];
>  					curr_channel_index = k;
> -					if(0 == index) {
> +					if (0 == index)
>  						curr_info->last_event = NULL;
> -					}
>  					break;
>  				}
>  			}
> -			if(k == guide.num_channels) {
> -				fprintf(stderr, "%s(): cannot find source_id "
> -					"0x%04X in the EIT\n",
> -					__FUNCTION__, source_id);
> +			if (k == guide.num_channels) {
> +				error_msg("cannot find source_id 0x%04X in the EIT", source_id);
>  				return -1;
>  			}
>  			} else {
> -				if(source_id !=
> -					atsc_eit_section_source_id(eit)) {
> +				if (source_id != atsc_eit_section_source_id(eit))
>  					continue;
> -				}
>  			}
> -			if(eit_instance_pattern & (1 << curr_channel_index)) {
> -				/* we have received this instance,
> -				 * so quit quick
> -				 */
> +			/* if we have received this instance, quit quick */
> +			if (eit_instance_pattern & (1 << curr_channel_index))
>  				break;
> -			}
>  
> -			if(-1 == num_sections) {
> -				num_sections = 1 +
> -					eit->head.ext_head.last_section_number;
> -				if(32 < num_sections) {
> -					fprintf(stderr,
> -						"%s(): no support yet for "
> -						"tables having more than "
> -						"32 sections\n", __FUNCTION__);
> +			if (-1 == num_sections) {
> +				num_sections = 1 + eit->head.ext_head.last_section_number;
> +				if (32 < num_sections) {
> +					error_msg("no support yet for tables having more than 32 sections");
>  					return -1;
>  				}
>  			} else {
> -				if(num_sections != 1 +
> -					eit->head.ext_head.last_section_number) {
> -					fprintf(stderr,
> -						"%s(): last section number "
> -						"does not match\n",
> -						__FUNCTION__);
> +				if (num_sections != 1 + eit->head.ext_head.last_section_number) {
> +					error_msg("last section number does not match");
>  					return -1;
>  				}
>  			}
> -			if(section_pattern &
> -				(1 << eit->head.ext_head.section_number)) {
> +			if (section_pattern & (1 << eit->head.ext_head.section_number))
>  				continue;
> -			}
>  			section_pattern |= 1 << eit->head.ext_head.section_number;
>  
>  			eit_info = &curr_info->eit[index];
> -			if(NULL == (eit_info->section =
> -				realloc(eit_info->section,
> -				(eit_info->num_eit_sections + 1) *
> -				sizeof(struct atsc_eit_section_info)))) {
> -				fprintf(stderr,
> -					"%s(): error calling realloc()\n",
> -					__FUNCTION__);
> +			eit_info->section = realloc(eit_info->section, (eit_info->num_eit_sections + 1) * sizeof(struct atsc_eit_section_info));
> +			if (NULL == eit_info->section) {
> +				error_msg("error calling realloc()");
>  				return -1;
>  			}
>  			section_num = eit->head.ext_head.section_number;
> -			if(0 == eit_info->num_eit_sections) {
> +			if (0 == eit_info->num_eit_sections) {
>  				eit_info->num_eit_sections = 1;
>  				section = eit_info->section;
>  			} else {
> -				/* have to sort it into section order
> -				 * (temporal order)
> -				 */
> -				for(i = 0; i < eit_info->num_eit_sections; i++) {
> -					if(eit_info->section[i].section_num >
> -						section_num) {
> +				/* have to sort it into section order (temporal order) */
> +				for (i = 0; i < eit_info->num_eit_sections; i++) {
> +					if (eit_info->section[i].section_num > section_num)
>  						break;
> -					}
>  				}
> -				memmove(&eit_info->section[i + 1],
> -					&eit_info->section[i],
> -					(eit_info->num_eit_sections - i) *
> -					sizeof(struct atsc_eit_section_info));
> +				memmove(&eit_info->section[i + 1], &eit_info->section[i], (eit_info->num_eit_sections - i) * sizeof(struct atsc_eit_section_info));
>  				section = &eit_info->section[i - 1];
>  				section = &eit_info->section[i];
>  				eit_info->num_eit_sections += 1;
> @@ -797,33 +730,31 @@ static int parse_eit(int dmxfd, int inde
>  			section->num_events = eit->num_events_in_section;
>  			section->num_etms = 0;
>  			section->num_received_etms = 0;
> -			if(NULL == (section->events = calloc(section->num_events,
> -				sizeof(struct atsc_event_info *)))) {
> -				fprintf(stderr, "%s(): error calling calloc()\n",
> -					__FUNCTION__);
> +			section->events = calloc(section->num_events, sizeof(struct atsc_event_info *));
> +			if (NULL == section->events) {
> +				error_msg("error calling calloc()");
>  				return -1;
>  			}
> -			if(parse_events(curr_info, eit, section)) {
> -				fprintf(stderr, "%s(): error calling "
> -					"parse_events()\n", __FUNCTION__);
> +			if (parse_events(curr_info, eit, section)) {
> +				error_msg("error calling parse_events()");
>  				return -1;
>  			}
> -		} while(section_pattern != (uint32_t)((1 << num_sections) - 1));
> +		} while (section_pattern != (uint32_t)((1 << num_sections) - 1));
>  		eit_instance_pattern |= 1 << curr_channel_index;
>  	}
>  
> -	for(i = 0; i < guide.num_channels; i++) {
> +	for (i = 0; i < guide.num_channels; i++) {
>  		struct atsc_channel_info *channel = &guide.ch[i];
>  		struct atsc_eit_info *ei = &channel->eit[index];
>  		struct atsc_eit_section_info *s;
>  
> -		if(0 == ei->num_eit_sections) {
> +		if (0 == ei->num_eit_sections) {
>  			channel->last_event = NULL;
>  			continue;
>  		}
>  		s = &ei->section[ei->num_eit_sections - 1];
>  		/* BUG: it's incorrect when last section has no event */
> -		if(0 == s->num_events) {
> +		if (0 == s->num_events) {
>  			channel->last_event = NULL;
>  			continue;
>  		}
> @@ -841,12 +772,11 @@ static int parse_mgt(int dmxfd)
>  	int i, j, ret;
>  
>  	ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&mgt);
> -	if(0 > ret) {
> -		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> -			__FUNCTION__);
> +	if (0 > ret) {
> +		error_msg("error calling atsc_scan_table()");
>  		return -1;
>  	}
> -	if(0 == ret) {
> +	if (0 == ret) {
>  		fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
>  		return 0;
>  	}
> @@ -855,31 +785,28 @@ static int parse_mgt(int dmxfd)
>  	atsc_mgt_section_tables_for_each(mgt, t, i) {
>  		struct mgt_table_name table;
>  
> -	for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
> -		sizeof(struct mgt_table_name)); j++) {
> -		if(t->table_type > mgt_tab_name_array[j].range) {
> -			continue;
> -		}
> -		table = mgt_tab_name_array[j];
> -		if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
> -			mgt_tab_name_array[j].range) {
> -			j = -1;
> -		} else {
> -			j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
> -			if(0x017F == table.range) {
> -				guide.eit_pid[j] = t->table_type_PID;
> -			} else if (0x027F == table.range) {
> -				guide.ett_pid[j] = t->table_type_PID;
> +		for (j = 0; j < (int)(sizeof(mgt_tab_name_array) / sizeof(struct mgt_table_name)); j++) {
> +			if (t->table_type > mgt_tab_name_array[j].range)
> +				continue;
> +			table = mgt_tab_name_array[j];
> +			if (0 == j || mgt_tab_name_array[j - 1].range + 1 ==
> +				mgt_tab_name_array[j].range) {
> +				j = -1;
> +			} else {
> +				j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
> +				if (0x017F == table.range) {
> +					guide.eit_pid[j] = t->table_type_PID;
> +				} else if (0x027F == table.range) {
> +					guide.ett_pid[j] = t->table_type_PID;
> +				}
>  			}
> +			break;
>  		}
> -		break;
> -	}
>  
>  		fprintf(stdout, "  %2d: type = 0x%04X, PID = 0x%04X, %s", i,
> -		    t->table_type, t->table_type_PID, table.string);
> -		if(-1 != j) {
> -		    fprintf(stdout, " %d", j);
> -		}
> +			t->table_type, t->table_type_PID, table.string);
> +		if (-1 != j)
> +			fprintf(stdout, " %d", j);
>  		fprintf(stdout, "\n");
>  	}
>  
> @@ -890,32 +817,24 @@ static int cleanup_guide(void)
>  {
>  	int i, j, k;
>  
> -	for(i = 0; i < guide.num_channels; i++) {
> +	for (i = 0; i < guide.num_channels; i++) {
>  		struct atsc_channel_info *channel = &guide.ch[i];
>  
> -		if(channel->title_buf.string) {
> +		if (channel->title_buf.string)
>  			free(channel->title_buf.string);
> -		}
> -		if(channel->msg_buf.string) {
> +		if (channel->msg_buf.string)
>  			free(channel->msg_buf.string);
> -		}
> -		for(j = 0; j < channel->num_eits; j++) {
> +		for (j = 0; j < channel->num_eits; j++) {
>  			struct atsc_eit_info *eit = &channel->eit[j];
>  
> -			for(k = 0; k < eit->num_eit_sections; k++) {
> -				struct atsc_eit_section_info *section =
> -					&eit->section[k];
> -				if(section->num_events) {
> +			for (k = 0; k < eit->num_eit_sections; k++) {
> +				struct atsc_eit_section_info *section = &eit->section[k];
> +				if (section->num_events)
>  					free(section->events);
> -				}
> -			}
> -			if(k) {
> -				free(eit->section);
>  			}
> +			if (k) free(eit->section);
>  		}
> -		if(j) {
> -			free(channel->eit);
> -		}
> +		if (j) free(channel->eit);
>  	}
>  
>  	return 0;
> @@ -927,38 +846,33 @@ static int print_events(struct atsc_chan
>  	int m;
>  	char line[256];
>  
> -	if(NULL == section) {
> -		fprintf(stderr, "%s(): NULL pointer detected", __FUNCTION__);
> +	if (NULL == section) {
> +		error_msg("NULL pointer detected");
>  		return -1;
>  	}
> -	for(m = 0; m < section->num_events; m++) {
> +	for (m = 0; m < section->num_events; m++) {
>  		struct atsc_event_info *event =
>  			section->events[m];
>  
> -		if(NULL == event) {
> +		if (NULL == event)
>  			continue;
> -		}
> -		fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
> -			event->start.tm_hour, event->start.tm_min,
> -			event->end.tm_hour, event->end.tm_min);
> -		snprintf(line, event->title_len, "%s",
> -			&channel->title_buf.string[event->title_pos]);
> -		line[event->title_len] = '\0';
> +		fprintf(stdout, "|%02d:%02d--%02d:%02d| ", event->start.tm_hour, event->start.tm_min, event->end.tm_hour, event->end.tm_min);
> +		snprintf(line, event->title_len + 1, "%s", &channel->title_buf.string[event->title_pos]);
> +		/*line[event->title_len] = '\0';*/
>  		fprintf(stdout, "%s\n", line);
> -		if(event->msg_len) {
> +		if (event->msg_len) {
>  			int len = event->msg_len;
>  			int pos = event->msg_pos;
>  			size_t part;
>  
>  			do {
>  				part = len > 255 ? 255 : len;
> -				snprintf(line, part, "%s",
> -					&channel->msg_buf.string[pos]);
> -				line[part] = '\0';
> +				snprintf(line, part + 1, "%s", &channel->msg_buf.string[pos]);
> +				/*line[part] = '\0';*/
>  				fprintf(stdout, "%s", line);
>  				len -= part;
>  				pos += part;
> -			} while(0 < len);
> +			} while (0 < len);
>  			fprintf(stdout, "\n");
>  		}
>  	}
> @@ -970,20 +884,17 @@ static int print_guide(void)
>  	int i, j, k;
>  
>  	fprintf(stdout, "%s\n", separator);
> -	for(i = 0; i < guide.num_channels; i++) {
> +	for (i = 0; i < guide.num_channels; i++) {
>  		struct atsc_channel_info *channel = &guide.ch[i];
>  
> -		fprintf(stdout, "%d.%d  %s\n", channel->major_num,
> -			channel->minor_num, channel->short_name);
> -		for(j = 0; j < channel->num_eits; j++) {
> +		fprintf(stdout, "%d.%d  %s\n", channel->major_num, channel->minor_num, channel->short_name);
> +		for (j = 0; j < channel->num_eits; j++) {
>  			struct atsc_eit_info *eit = &channel->eit[j];
>  
> -			for(k = 0; k < eit->num_eit_sections; k++) {
> -				struct atsc_eit_section_info *section =
> -					&eit->section[k];
> -				if(print_events(channel, section)) {
> -					fprintf(stderr, "%s(): error calling "
> -						"print_events()\n", __FUNCTION__);
> +			for (k = 0; k < eit->num_eit_sections; k++) {
> +				struct atsc_eit_section_info *section = &eit->section[k];
> +				if (print_events(channel, section)) {
> +					error_msg("error calling print_events()");
>  					return -1;
>  				}
>  			}
> @@ -996,9 +907,8 @@ static int print_guide(void)
>  
>  static int open_demux(int *dmxfd)
>  {
> -	if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
> -		fprintf(stderr, "%s(): error calling dvbdemux_open_demux()\n",
> -			__FUNCTION__);
> +	if ((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
> +		error_msg("error calling dvbdemux_open_demux()");
>  		return -1;
>  	}
>  	return 0;
> @@ -1006,9 +916,8 @@ static int open_demux(int *dmxfd)
>  
>  static int close_demux(int dmxfd)
>  {
> -	if(dvbdemux_stop(dmxfd)) {
> -		fprintf(stderr, "%s(): error calling dvbdemux_stop()\n",
> -			__FUNCTION__);
> +	if (dvbdemux_stop(dmxfd)) {
> +		error_msg("error calling dvbdemux_stop()");
>  		return -1;
>  	}
>  	return 0;
> @@ -1033,60 +942,52 @@ static int atsc_scan_table(int dmxfd, ui
>  	memset(mask, 0, sizeof(mask));
>  	filter[0] = tag;
>  	mask[0] = 0xFF;
> -	if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
> -		fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
> -			__FUNCTION__);
> +	if (dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
> +		error_msg("error calling atsc_scan_table()");
>  		return -1;
>  	}
>  
>  	/* poll for data */
>  	pollfd.fd = dmxfd;
>  	pollfd.events = POLLIN | POLLERR |POLLPRI;
> -	if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
> -		if(ctrl_c) {
> +	if ((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
> +		if (ctrl_c)
>  			return 0;
> -		}
> -		fprintf(stderr, "%s(): error calling poll()\n", __FUNCTION__);
> +		error_msg("error calling poll()");
>  		return -1;
>  	}
>  
> -	if(0 == ret) {
> +	if (0 == ret)
>  		return 0;
> -	}
>  
>  	/* read it */
> -	if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
> -		fprintf(stderr, "%s(): error calling read()\n", __FUNCTION__);
> +	if ((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
> +		error_msg("error calling read()");
>  		return -1;
>  	}
>  
>  	/* parse section */
>  	section = section_codec(sibuf, size);
> -	if(NULL == section) {
> -		fprintf(stderr, "%s(): error calling section_codec()\n",
> -			__FUNCTION__);
> +	if (NULL == section) {
> +		error_msg("error calling section_codec()");
>  		return -1;
>  	}
>  
>  	section_ext = section_ext_decode(section, 0);
> -	if(NULL == section_ext) {
> -		fprintf(stderr, "%s(): error calling section_ext_decode()\n",
> -			__FUNCTION__);
> +	if (NULL == section_ext) {
> +		error_msg("error calling section_ext_decode()");
>  		return -1;
>  	}
>  
>  	psip = atsc_section_psip_decode(section_ext);
> -	if(NULL == psip) {
> -		fprintf(stderr,
> -			"%s(): error calling atsc_section_psip_decode()\n",
> -			__FUNCTION__);
> +	if (NULL == psip) {
> +		error_msg("error calling atsc_section_psip_decode()");
>  		return -1;
>  	}
>  
>  	*table_section = table_callback[tag & 0x0F](psip);
> -	if(NULL == *table_section) {
> -		fprintf(stderr, "%s(): error decode table section\n",
> -			__FUNCTION__);
> +	if (NULL == *table_section) {
> +		error_msg("error decode table section");
>  		return -1;
>  	}
>  
> @@ -1100,17 +1001,16 @@ int main(int argc, char *argv[])
>  
>  	program = argv[0];
>  
> -	if(1 == argc) {
> +	if (1 == argc) {
>  		usage();
>  		exit(-1);
>  	}
>  
> -	for( ; ; ) {
> +	for ( ; ; ) {
>  		char c;
>  
> -		if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
> +		if (-1 == (c = getopt(argc, argv, "a:f:p:m:th")))
>  			break;
> -		}
>  
>  		switch(c) {
>  		case 'a':
> @@ -1124,9 +1024,8 @@ int main(int argc, char *argv[])
>  		case 'p':
>  			period = strtol(optarg, NULL, 0);
>  			/* each table covers 3 hours */
> -			if((3 * MAX_NUM_EVENT_TABLES) < period) {
> +			if ((3 * MAX_NUM_EVENT_TABLES) < period)
>  				period = 3 * MAX_NUM_EVENT_TABLES;
> -			}
>  			break;
>  
>  		case 'm':
> @@ -1154,94 +1053,81 @@ int main(int argc, char *argv[])
>  	memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
>  	memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
>  
> -	if(open_frontend(&fe)) {
> -		fprintf(stderr, "%s(): error calling open_frontend()\n",
> -			__FUNCTION__);
> +	if (open_frontend(&fe)) {
> +		error_msg("error calling open_frontend()");
>  		return -1;
>  	}
>  
> -	if(open_demux(&dmxfd)) {
> -		fprintf(stderr, "%s(): error calling open_demux()\n",
> -			__FUNCTION__);
> +	if (open_demux(&dmxfd)) {
> +		error_msg("error calling open_demux()");
>  		return -1;
>  	}
>  
> -	if(parse_stt(dmxfd)) {
> -		fprintf(stderr, "%s(): error calling parse_stt()\n",
> -			__FUNCTION__);
> +	if (parse_stt(dmxfd)) {
> +		error_msg("error calling parse_stt()");
>  		return -1;
>  	}
>  
> -	if(parse_mgt(dmxfd)) {
> -		fprintf(stderr, "%s(): error calling parse_mgt()\n",
> -			__FUNCTION__);
> +	if (parse_mgt(dmxfd)) {
> +		error_msg("error calling parse_mgt()");
>  		return -1;
>  	}
>  
> -	if(parse_tvct(dmxfd)) {
> -		fprintf(stderr, "%s(): error calling parse_tvct()\n",
> -			__FUNCTION__);
> +	if (parse_tvct(dmxfd)) {
> +		error_msg("error calling parse_tvct()");
>  		return -1;
>  	}
>  
>  #ifdef ENABLE_RRT
> -	if(parse_rrt(dmxfd)) {
> -		fprintf(stderr, "%s(): error calling parse_rrt()\n",
> -			__FUNCTION__);
> +	if (parse_rrt(dmxfd)) {
> +		error_msg("error calling parse_rrt()");
>  		return -1;
>  	}
>  #endif
>  
>  	fprintf(stdout, "receiving EIT ");
> -	for(i = 0; i < guide.ch[0].num_eits; i++) {
> -		if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
> -			fprintf(stderr, "%s(): error calling parse_eit()\n",
> -				__FUNCTION__);
> +	for (i = 0; i < guide.ch[0].num_eits; i++) {
> +		if (parse_eit(dmxfd, i, guide.eit_pid[i])) {
> +			error_msg("error calling parse_eit()");
>  			return -1;
>  		}
>  	}
>  	fprintf(stdout, "\n");
>  
>  	old_handler = signal(SIGINT, int_handler);
> -	if(enable_ett) {
> +	if (enable_ett) {
>  		fprintf(stdout, "receiving ETT ");
> -		for(i = 0; i < guide.ch[0].num_eits; i++) {
> -			if(0xFFFF != guide.ett_pid[i]) {
> -				if(parse_ett(dmxfd, i, guide.ett_pid[i])) {
> -					fprintf(stderr, "%s(): error calling "
> -						"parse_eit()\n", __FUNCTION__);
> +		for (i = 0; i < guide.ch[0].num_eits; i++) {
> +			if (0xFFFF != guide.ett_pid[i]) {
> +				if (parse_ett(dmxfd, i, guide.ett_pid[i])) {
> +					error_msg("error calling parse_eit()");
>  					return -1;
>  				}
>  			}
> -			if(ctrl_c) {
> +			if (ctrl_c)
>  				break;
> -			}
>  		}
>  		fprintf(stdout, "\n");
>  	}
>  	signal(SIGINT, old_handler);
>  
> -	if(print_guide()) {
> -		fprintf(stderr, "%s(): error calling print_guide()\n",
> -			__FUNCTION__);
> +	if (print_guide()) {
> +		error_msg("error calling print_guide()");
>  		return -1;
>  	}
>  
> -	if(cleanup_guide()) {
> -		fprintf(stderr, "%s(): error calling cleanup_guide()\n",
> -			__FUNCTION__);
> +	if (cleanup_guide()) {
> +		error_msg("error calling cleanup_guide()");
>  		return -1;
>  	}
>  
> -	if(close_demux(dmxfd)) {
> -		fprintf(stderr, "%s(): error calling close_demux()\n",
> -			__FUNCTION__);
> +	if (close_demux(dmxfd)) {
> +		error_msg("error calling close_demux()");
>  		return -1;
>  	}
>  
> -	if(close_frontend(fe)) {
> -		fprintf(stderr, "%s(): error calling close_demux()\n",
> -			__FUNCTION__);
> +	if (close_frontend(fe)) {
> +		error_msg("error calling close_demux()");
>  		return -1;
>  	}
>  
> diff -upr dvb-apps/util/scan/Makefile dvb-apps_local/util/scan/Makefile
> --- dvb-apps/util/scan/Makefile	2009-06-22 12:13:04.171925478 -0500
> +++ dvb-apps_local/util/scan/Makefile	2009-06-22 12:17:48.000000000 -0500
> @@ -14,7 +14,7 @@ inst_bin = $(binaries)
>  
>  removing = atsc_psip_section.c atsc_psip_section.h
>  
> -CPPFLAGS += -DDATADIR=\"$(prefix)/share\"
> +CPPFLAGS += -Wno-packed-bitfield-compat -D__KERNEL_STRICT_NAMES -DDATADIR=\"$(prefix)/share\"
>  
>  .PHONY: all



^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2009-06-23  0:56 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-17 23:18 [Patch] New utility program atsc_epg added to dvb-apps utility suite Yufei Yuan
2009-06-17 23:51 ` hermann pitton
     [not found]   ` <ccdf9f470906171706gc36e43bq4e2092d948c1fbf5@mail.gmail.com>
     [not found]     ` <1245284055.8827.36.camel@pc07.localdom.local>
     [not found]       ` <ccdf9f470906171720i4076642dna483643c55a4a85f@mail.gmail.com>
2009-06-18  0:52         ` hermann pitton
     [not found]         ` <1245285015.10476.4.camel@pc07.localdom.local>
     [not found]           ` <ccdf9f470906171746k8e5ac37j9c0a48823f98ba87@mail.gmail.com>
2009-06-18  1:05             ` hermann pitton
2009-06-18  1:12               ` Yufei Yuan
2009-06-18  1:23                 ` hermann pitton
2009-06-18  8:32 ` Manu Abraham
2009-06-18  8:48   ` Manu Abraham
2009-06-18 13:06     ` Yufei Yuan
2009-06-19  0:52       ` Yufei Yuan
2009-06-19  1:39         ` Yufei Yuan
2009-06-20  0:41           ` hermann pitton
2009-06-20  1:00             ` Yufei Yuan
2009-06-20  1:28               ` hermann pitton
2009-06-20  2:38                 ` Yufei Yuan
2009-06-20  3:04                   ` hermann pitton
     [not found]           ` <ccdf9f470906181855m2d6c471cm12afea3f228fd57c@mail.gmail.com>
2009-06-20  7:30             ` Manu Abraham
2009-06-20 13:30               ` Yufei Yuan
2009-06-20 17:15               ` [Patch] dvb-apps: code cleanup and bug fix Yufei Yuan
2009-06-20 17:31                 ` Yufei Yuan
2009-06-22 23:43               ` [Patch] New utility program atsc_epg added to dvb-apps utility suite Yufei Yuan
2009-06-23  0:52                 ` hermann pitton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.