예제 #1
0
파일: pdc1.c 프로젝트: mwgoldsmith/zvbi
/* Attention! This function returns a static string. */
static const char *
pil_str				(vbi_pil		pil)
{
    static char buffer[32];

    switch (pil) {
    case VBI_PIL_TIMER_CONTROL:
        return "TC";
    case VBI_PIL_INHIBIT_TERMINATE:
        return "RI/T";
    case VBI_PIL_INTERRUPTION:
        return "INT";
    case VBI_PIL_CONTINUE:
        return "CONT";
    case VBI_PIL_NSPV:
        return "NSPV/END";

    default:
        snprintf (buffer, sizeof (buffer),
                  "%02u%02uT%02u%02u",
                  VBI_PIL_MONTH (pil),
                  VBI_PIL_DAY (pil),
                  VBI_PIL_HOUR (pil),
                  VBI_PIL_MINUTE (pil));
        return buffer;
    }
}
예제 #2
0
파일: pdc.c 프로젝트: OpenDMM/zvbi
static vbi_bool
valid_pil_lto_validity_window	(time_t *		begin,
				 time_t *		end,
				 vbi_pil		pil,
				 time_t			start,
				 int			seconds_east)
{
	time_t t;

	t = valid_pil_lto_to_time (pil & VBI_PIL (/* month */ 15,
						   /* day */ 31,
						   /* hour */ 0,
						   /* minute */ 0),
				   start, seconds_east);
	if (unlikely ((time_t) -1 == t)) {
		if (VBI_ERR_INVALID_PIL == errno) {
			/* Annex F: "Invalid days -
			   indefinite time window". */
			*begin = TIME_MIN;
			*end = TIME_MAX;
			return TRUE;
		} else {
			return FALSE;
		}
	}

	/* EN 300 231 Section 9.3. */

	/* Just adding a number of seconds is safe because UTC does
	   not observe DST and POSIX time_t does not count leap
	   seconds. The results are unambiguous because leap seconds
	   are inserted or removed just before midnight and we only
	   return full hours. */

	if (unlikely (t > TIME_MAX - 28 * 60 * 60)) {
		errno = EOVERFLOW;
		return FALSE;
	}

	if (VBI_PIL_HOUR (pil) < 4) {
		if (unlikely (t < 4 * 60 * 60)) {
			errno = EOVERFLOW;
			return FALSE;
		}

		*begin = t - 4 * 60 * 60;
	} else {
		*begin = t;
	}

	*end = t + 28 * 60 * 60;

	return TRUE;
}
예제 #3
0
파일: pdc.c 프로젝트: OpenDMM/zvbi
/**
 * @param pil Program Identification Label.
 *
 * Determines if @a pil represents a valid date and time.
 *
 * Since PILs have no year field February 29th is considered valid.
 * You can find out if this date is valid in a given year with the
 * vbi_pil_to_time() function.
 *
 * 24:00 is not valid (an unreal hour) as defined in EN 300 231
 * Annex F and EIA 608-B Section 9.5.1.1.
 *
 * @returns
 * @c TRUE if @a pil represents a valid date and time, @c FALSE
 * if @a pil contains an unreal date or time (e.g. Jan 0 27:61),
 * a service code or unallocated code.
 *
 * @since 0.2.34
 */
vbi_bool
vbi_pil_is_valid_date		(vbi_pil		pil)
{
	unsigned int month;
	unsigned int day;

	month = VBI_PIL_MONTH (pil);
	day = VBI_PIL_DAY (pil);

	/* Note this also checks for zero month and day. */
	return (month - 1 < 12
		&& day - 1 < month_days[month - 1]
		&& VBI_PIL_HOUR (pil) < 24
		&& VBI_PIL_MINUTE (pil) < 60);
}
예제 #4
0
파일: pdc.c 프로젝트: OpenDMM/zvbi
/**
 * @internal
 * @param pil vbi_pil to print.
 * @param fp Destination stream.
 *
 * Prints a vbi_pil as service code or date and time string without
 * trailing newline. This is intended for debugging.
 */
void
_vbi_pil_dump			(vbi_pil		pil,
				 FILE *			fp)
{
	switch (pil) {
	case VBI_PIL_TIMER_CONTROL:
		fputs ("TC", fp);
		break;

	case VBI_PIL_INHIBIT_TERMINATE:
		fputs ("RI/T", fp);
		break;

	case VBI_PIL_INTERRUPTION:
		fputs ("INT", fp);
		break;

	case VBI_PIL_CONTINUE:
		fputs ("CONT", fp);
		break;

	case VBI_PIL_NSPV:
		/* VBI_PIL_NSPV (PDC) == VBI_PIL_END (XDS) */
		fputs ("NSPV/END", fp);
		break;

	default:
		fprintf (fp, "%05x (%02u-%02u %02u:%02u)",
			 pil,
			 VBI_PIL_MONTH (pil),
			 VBI_PIL_DAY (pil),
			 VBI_PIL_HOUR (pil),
			 VBI_PIL_MINUTE (pil));
		break;
	}
}
예제 #5
0
파일: pdc.c 프로젝트: OpenDMM/zvbi
/**
 * @param pil Program Identification Label (PIL) to convert.
 * @param start The most recently announced start time of the
 *   program. If zero the current system time will be used.
 * @param tz A time zone name in the same format as the TZ environment
 *   variable. If @c NULL the current value of TZ will be used.
 *
 * This function converts a PIL to a time_t in the same manner
 * localtime() converts a broken-down time to time_t.
 *
 * Since PILs do not contain a year field, the year is determined from
 * the @a start parameter, that is the most recently announced start
 * time of the program or "AT-1" in EN 300 231 parlance. If @a pil
 * contains a month more than five months after @a start, @a pil is
 * assumed to refer to an earlier date than @a start.
 *
 * @a pil is assumed to be a time in the time zone @a tz. @a start
 * will be converted to a local time in the same time zone to
 * determine the correct year.
 *
 * Teletext packet 8/30 format 2, VPS and DVB PDC descriptors give a
 * PIL relative to the time zone of the intended audience of the
 * program. Ideally the time zone would be specified as a geographic
 * area like "Europe/London", such that the function can determine
 * the correct offset from UTC and if daylight-saving time is in
 * effect at the specified date. See the documentation of the
 * localtime() function and the TZ environment variable for details.
 *
 * XDS Current/Future Program ID packets give a PIL relative to UTC.
 * Just specify time zone "UTC" in this case.
 *
 * @returns
 * The PIL as a time_t, that is the number of seconds since
 * 1970-01-01 00:00 UTC. On error the function
 * returns (time_t) -1:
 * - @a pil does not contain a valid date or time. February 29th is
 *   a valid date only if the estimated year is a leap year.
 * - @a tz is empty or contains an equal sign '='.
 * - @a start is zero and the current system time could not be
 *   determined.
 * - The time specified by @a pil, @a start and @a tz cannot be
 *   represented as a time_t value.
 * - Insufficient memory was available.
 *
 * @since 0.2.34
 *
 * @bug
 * This function is not thread safe unless @a tz is @c NULL. That is
 * a limitation of the C library which permits the conversion of a
 * broken-down time in an arbitrary time zone only by setting the TZ
 * environment variable. The function may also fail to restore the
 * value of TZ if insufficient memory is available.
 */
time_t
vbi_pil_to_time			(vbi_pil		pil,
				 time_t			start,
				 const char *		tz)
{
	struct tm tm;
	char *old_tz;
	time_t result;
	int saved_errno;

	if (unlikely (!vbi_pil_is_valid_date (pil))) {
#if 3 == VBI_VERSION_MINOR
		errno = VBI_ERR_INVALID_PIL;
#else
		errno = 0;
#endif
		return (time_t) -1;
	}

	if (NULL != tz && 0 == strcmp (tz, "UTC")) {
		time_t t;

		t = valid_pil_lto_to_time (pil, start,
					   /* seconds_east */ 0);
#if 2 == VBI_VERSION_MINOR
		errno = 0;
#endif
		return t;
	}

	if (unlikely (!localtime_tz (&tm, &old_tz, start, tz))) {
#if 2 == VBI_VERSION_MINOR
		errno = 0;
#endif
		return (time_t) -1;
	}

	if (unlikely (!tm_mon_mday_from_pil (&tm, pil))) {
		saved_errno = EOVERFLOW;
		goto failed;
	}

	if (unlikely (!tm_leap_day_check (&tm))) {
		saved_errno = VBI_ERR_INVALID_PIL;
		goto failed;
	}

	tm.tm_hour = VBI_PIL_HOUR (pil);
	tm.tm_min = VBI_PIL_MINUTE (pil);
	tm.tm_sec = 0;

	tm.tm_isdst = -1; /* unknown */

	result = mktime (&tm);
	if (unlikely ((time_t) -1 == result))
		goto failed;

	if (unlikely (!restore_tz (&old_tz, tz))) {
#if 2 == VBI_VERSION_MINOR
		errno = 0;
#endif
		return (time_t) -1;
	}

	return result;

 failed:
	if (unlikely (!restore_tz (&old_tz, tz))) {
#if 2 == VBI_VERSION_MINOR
		errno = 0;
#endif
		return (time_t) -1;
	}

#if 3 == VBI_VERSION_MINOR
	errno = saved_errno;
#else
	errno = 0;
#endif
	return (time_t) -1;
}
예제 #6
0
파일: pdc.c 프로젝트: OpenDMM/zvbi
static time_t
valid_pil_lto_to_time		(vbi_pil		pil,
				 time_t			start,
				 int			seconds_east)
{
	struct tm tm;

	/* Some system calls below may not set errno on failure, but
	   we must distinguish those errors from VBI_ERR_INVALID_PIL
	   for valid_pil_lto_validity_window(). */
	errno = 0;

	CLEAR (tm);

	if ((time_t) -1 == start) {
		if (unlikely ((time_t) -1 == time (&start))) {
			/* time() can fail but POSIX defines no
			   error code. On Linux EFAULT is possible. */
			if (0 == errno)
				errno = VBI_ERR_NO_TIME;
			return (time_t) -1;
		}
	}

	if (seconds_east < 0) {
		/* Note start can be negative. */
		if (unlikely (start < -seconds_east)) {
			errno = EOVERFLOW;
			return (time_t) -1;
		}
	} else {
		if (unlikely (start > TIME_MAX - seconds_east)) {
			errno = EOVERFLOW;
			return (time_t) -1;
		}
	}

	start += seconds_east;

	if (unlikely (NULL == gmtime_r (&start, &tm)))
		return (time_t) -1;

	if (unlikely (!tm_mon_mday_from_pil (&tm, pil))) {
		errno = EOVERFLOW;
		return (time_t) -1;
	}

	if (unlikely (!tm_leap_day_check (&tm))) {
		errno = VBI_ERR_INVALID_PIL;
		return (time_t) -1;
	}

	tm.tm_hour = VBI_PIL_HOUR (pil);
	tm.tm_min = VBI_PIL_MINUTE (pil);
	tm.tm_sec = 0;

	start = timegm (&tm);
	if (unlikely ((time_t) -1 == start))
		return (time_t) -1;

	if (seconds_east > 0) {
		/* Note start can be negative. */
		if (unlikely (start < seconds_east)) {
			errno = EOVERFLOW;
			return (time_t) -1;
		}
	} else {
		if (unlikely (start > TIME_MAX + seconds_east)) {
			errno = EOVERFLOW;
			return (time_t) -1;
		}
	}

	return start - seconds_east;
}
예제 #7
0
파일: pdc.c 프로젝트: OpenDMM/zvbi
static vbi_bool
valid_pil_validity_window	(time_t *		begin,
				 time_t *		end,
				 vbi_pil		pil,
				 time_t			start,
				 const char *		tz)
{
	char *old_tz;
	struct tm tm;
	struct tm tm2;
	time_t stop;
	int saved_errno;

	/* EN 300 231 Section 9.3 and Annex F. */

	old_tz = NULL;

	if (NULL != tz && 0 == strcmp (tz, "UTC")) {
		return valid_pil_lto_validity_window
			(begin, end, pil, start, /* seconds_east */ 0);
	}

	if (unlikely (!localtime_tz (&tm, &old_tz, start, tz)))
		return FALSE;

	if (unlikely (!tm_mon_mday_from_pil (&tm, pil))) {
		saved_errno = EOVERFLOW;
		goto failed;
	}

	if (unlikely (!tm_leap_day_check (&tm))) {
		/* Annex F: "Invalid days - indefinite time window". */
		if (!restore_tz (&old_tz, tz))
			return FALSE;
		*begin = TIME_MIN;
		*end = TIME_MAX;
		return TRUE;
	}

	tm.tm_hour = 0;
	tm.tm_min = 0;
	tm.tm_sec = 0;
	tm.tm_isdst = -1; /* unknown */

	tm2 = tm;

	if (VBI_PIL_HOUR (pil) < 4) {
		--tm.tm_mday;
		tm.tm_hour = 20;
	}

	start = mktime (&tm);
	if (unlikely ((time_t) -1 == start))
		goto failed;

	tm2.tm_mday += 1;
	tm2.tm_hour = 4;

	stop = mktime (&tm2);
	if (unlikely ((time_t) -1 == stop))
		goto failed;

	if (unlikely (!restore_tz (&old_tz, tz)))
		return FALSE;

	*begin = start;
	*end = stop;

	return TRUE;

 failed:
	if (unlikely (!restore_tz (&old_tz, tz)))
		return FALSE;

	errno = saved_errno;
	return FALSE;
}