r1122 - vdr/vdr/trunk/debian/patches
Thomas Günther
tom-guest at costa.debian.org
Thu Sep 1 00:18:56 UTC 2005
Author: tom-guest
Date: 2005-09-01 00:18:55 +0000 (Thu, 01 Sep 2005)
New Revision: 1122
Modified:
vdr/vdr/trunk/debian/patches/16_avoidTrashing.dpatch
Log:
Fixed unpatch 22_vdr-playerepg.dpatch (removed *.orig parts)
Modified: vdr/vdr/trunk/debian/patches/16_avoidTrashing.dpatch
===================================================================
--- vdr/vdr/trunk/debian/patches/16_avoidTrashing.dpatch 2005-08-31 21:35:11 UTC (rev 1121)
+++ vdr/vdr/trunk/debian/patches/16_avoidTrashing.dpatch 2005-09-01 00:18:55 UTC (rev 1122)
@@ -60,230 +60,6 @@
all: vdr
font: genfontfile\
fontfix-iso8859-1.c fontosd-iso8859-1.c fontsml-iso8859-1.c\
-diff -urNad vdr-1.3.31/Makefile.orig /tmp/dpep.cLVvp8/vdr-1.3.31/Makefile.orig
---- vdr-1.3.31/Makefile.orig 1970-01-01 01:00:00.000000000 +0100
-+++ /tmp/dpep.cLVvp8/vdr-1.3.31/Makefile.orig 2005-08-31 21:03:49.100196000 +0200
-@@ -0,0 +1,220 @@
-+#
-+# Makefile for the Video Disk Recorder
-+#
-+# See the main source file 'vdr.c' for copyright information and
-+# how to reach the author.
-+#
-+# $Id: Makefile 1.77 2005/08/14 11:42:20 kls Exp $
-+
-+.DELETE_ON_ERROR:
-+
-+CC ?= gcc
-+CFLAGS ?= -O2
-+
-+CXX ?= g++
-+CXXFLAGS ?= -fPIC -g -O2 -Wall -Woverloaded-virtual
-+
-+DVBDIR = ../DVB
-+LSIDIR = ./libsi
-+MANDIR = /usr/local/man
-+BINDIR = /usr/local/bin
-+LIBS = -ljpeg -lpthread -ldl -lcap
-+INCLUDES =
-+
-+PLUGINDIR= ./PLUGINS
-+PLUGINLIBDIR= $(PLUGINDIR)/lib
-+
-+VIDEODIR = /video
-+CFGDIR ?= $(VIDEODIR)
-+
-+DOXYGEN = /usr/bin/doxygen
-+DOXYFILE = Doxyfile
-+
-+-include Make.config
-+
-+INCLUDES += -I$(DVBDIR)/include
-+
-+SILIB = $(LSIDIR)/libsi.a
-+
-+OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbosd.o\
-+ dvbplayer.o dvbspu.o eit.o eitscan.o epg.o filter.o font.o i18n.o interface.o keys.o\
-+ lirc.o menu.o menuitems.o nit.o osdbase.o osd.o pat.o player.o plugin.o rcu.o\
-+ receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o\
-+ skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\
-+ timers.o tools.o transfer.o vdr.o videodir.o
-+
-+FIXFONT_ISO8859_1 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
-+OSDFONT_ISO8859_1 = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
-+SMLFONT_ISO8859_1 = -adobe-helvetica-medium-r-normal--18-*-100-100-p-*-iso8859-1
-+
-+FIXFONT_ISO8859_2 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-2
-+OSDFONT_ISO8859_2 = -adobe-helvetica-medium-r-normal--24-*-75-75-p-*-iso8859-2
-+SMLFONT_ISO8859_2 = -adobe-helvetica-medium-r-normal--18-*-75-75-p-*-iso8859-2
-+
-+FIXFONT_ISO8859_5 = -rfx-courier-bold-r-normal--24-*-75-75-m-*-iso8859-5
-+OSDFONT_ISO8859_5 = -rfx-helvetica-medium-r-normal--24-*-75-75-p-*-iso8859-5
-+SMLFONT_ISO8859_5 = -rfx-helvetica-medium-r-normal--18-*-75-75-p-*-iso8859-5
-+
-+FIXFONT_ISO8859_7 = --user-medium-r-normal--26-171-110-110-m-140-iso8859-7
-+OSDFONT_ISO8859_7 = --user-medium-r-normal--23-179-85-85-m-120-iso8859-7
-+SMLFONT_ISO8859_7 = --user-medium-r-normal--19-160-72-72-m-110-iso8859-7
-+
-+FIXFONT_ISO8859_15 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-15
-+OSDFONT_ISO8859_15 = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-15
-+SMLFONT_ISO8859_15 = -adobe-helvetica-medium-r-normal--18-*-100-100-p-*-iso8859-15
-+
-+ifndef NO_KBD
-+DEFINES += -DREMOTE_KBD
-+endif
-+ifdef REMOTE
-+DEFINES += -DREMOTE_$(REMOTE)
-+endif
-+
-+LIRC_DEVICE ?= /dev/lircd
-+RCU_DEVICE ?= /dev/ttyS1
-+
-+DEFINES += -DLIRC_DEVICE=\"$(LIRC_DEVICE)\" -DRCU_DEVICE=\"$(RCU_DEVICE)\"
-+
-+DEFINES += -DCMD_SUBMENUS
-+DEFINES += -D_GNU_SOURCE
-+
-+DEFINES += -DVIDEODIR=\"$(VIDEODIR)\"
-+DEFINES += -DCFGDIR=\"$(CFGDIR)\"
-+DEFINES += -DPLUGINDIR=\"$(PLUGINLIBDIR)\"
-+
-+# The version number of VDR (taken from VDR's "config.h"):
-+
-+VDRVERSION = $(shell grep 'define VDRVERSION ' config.h | awk '{ print $$3 }' | sed -e 's/"//g')
-+
-+ifdef VFAT
-+# for people who want their video directory on a VFAT partition
-+DEFINES += -DVFAT
-+endif
-+
-+all: vdr
-+font: genfontfile\
-+ fontfix-iso8859-1.c fontosd-iso8859-1.c fontsml-iso8859-1.c\
-+ fontfix-iso8859-2.c fontosd-iso8859-2.c fontsml-iso8859-2.c\
-+ fontfix-iso8859-5.c fontosd-iso8859-5.c fontsml-iso8859-5.c\
-+ fontfix-iso8859-7.c fontosd-iso8859-7.c fontsml-iso8859-7.c\
-+ fontfix-iso8859-15.c fontosd-iso8859-15.c fontsml-iso8859-15.c
-+ @echo "font files created."
-+
-+# Implicit rules:
-+
-+%.o: %.c
-+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
-+
-+# Dependencies:
-+
-+MAKEDEP = $(CXX) -MM -MG
-+DEPFILE = .dependencies
-+$(DEPFILE): Makefile
-+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
-+
-+-include $(DEPFILE)
-+
-+# The main program:
-+
-+vdr: $(OBJS) $(SILIB)
-+ $(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(NCURSESLIB) $(LIBS) $(LIBDIRS) $(SILIB) -o vdr
-+
-+# The font files:
-+
-+fontfix-iso8859-1.c:
-+ ./genfontfile "cFont::tPixelData FontFix_iso8859_1" "$(FIXFONT_ISO8859_1)" > $@
-+fontosd-iso8859-1.c:
-+ ./genfontfile "cFont::tPixelData FontOsd_iso8859_1" "$(OSDFONT_ISO8859_1)" > $@
-+fontsml-iso8859-1.c:
-+ ./genfontfile "cFont::tPixelData FontSml_iso8859_1" "$(SMLFONT_ISO8859_1)" > $@
-+
-+fontfix-iso8859-2.c:
-+ ./genfontfile "cFont::tPixelData FontFix_iso8859_2" "$(FIXFONT_ISO8859_2)" > $@
-+fontosd-iso8859-2.c:
-+ ./genfontfile "cFont::tPixelData FontOsd_iso8859_2" "$(OSDFONT_ISO8859_2)" > $@
-+fontsml-iso8859-2.c:
-+ ./genfontfile "cFont::tPixelData FontSml_iso8859_2" "$(SMLFONT_ISO8859_2)" > $@
-+
-+fontfix-iso8859-5.c:
-+ ./genfontfile "cFont::tPixelData FontFix_iso8859_5" "$(FIXFONT_ISO8859_5)" > $@
-+fontosd-iso8859-5.c:
-+ ./genfontfile "cFont::tPixelData FontOsd_iso8859_5" "$(OSDFONT_ISO8859_5)" > $@
-+fontsml-iso8859-5.c:
-+ ./genfontfile "cFont::tPixelData FontSml_iso8859_5" "$(SMLFONT_ISO8859_5)" > $@
-+
-+fontfix-iso8859-7.c:
-+ ./genfontfile "cFont::tPixelData FontFix_iso8859_7" "$(FIXFONT_ISO8859_7)" > $@
-+fontosd-iso8859-7.c:
-+ ./genfontfile "cFont::tPixelData FontOsd_iso8859_7" "$(OSDFONT_ISO8859_7)" > $@
-+fontsml-iso8859-7.c:
-+ ./genfontfile "cFont::tPixelData FontSml_iso8859_7" "$(SMLFONT_ISO8859_7)" > $@
-+
-+fontfix-iso8859-15.c:
-+ ./genfontfile "cFont::tPixelData FontFix_iso8859_15" "$(FIXFONT_ISO8859_15)" > $@
-+fontosd-iso8859-15.c:
-+ ./genfontfile "cFont::tPixelData FontOsd_iso8859_15" "$(OSDFONT_ISO8859_15)" > $@
-+fontsml-iso8859-15.c:
-+ ./genfontfile "cFont::tPixelData FontSml_iso8859_15" "$(SMLFONT_ISO8859_15)" > $@
-+
-+# The font file generator:
-+
-+genfontfile: genfontfile.c
-+ $(CC) $(CFLAGS) -o $@ -L/usr/X11R6/lib $< -lX11
-+
-+# The libsi library:
-+
-+$(SILIB):
-+ $(MAKE) -C $(LSIDIR) all
-+
-+# The 'include' directory (for plugins):
-+
-+include-dir:
-+ @mkdir -p include/vdr
-+ @(cd include/vdr; for i in ../../*.h; do ln -fs $$i .; done)
-+ @mkdir -p include/libsi
-+ @(cd include/libsi; for i in ../../libsi/*.h; do ln -fs $$i .; done)
-+
-+# Plugins:
-+
-+plugins: include-dir
-+ @for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do $(MAKE) -C "$(PLUGINDIR)/src/$$i" all; done
-+
-+plugins-clean:
-+ @for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do $(MAKE) -C "$(PLUGINDIR)/src/$$i" clean; done
-+ @-rm -f $(PLUGINLIBDIR)/libvdr-*.so.$(VDRVERSION)
-+
-+# Install the files:
-+
-+install:
-+ @mkdir -p $(BINDIR)
-+ @cp vdr runvdr $(BINDIR)
-+ @mkdir -p $(BINDIR)/$(PLUGINLIBDIR)
-+ @cp $(PLUGINLIBDIR)/* $(BINDIR)/$(PLUGINLIBDIR)
-+ @mkdir -p $(MANDIR)/man1
-+ @mkdir -p $(MANDIR)/man5
-+ @gzip -c vdr.1 > $(MANDIR)/man1/vdr.1.gz
-+ @gzip -c vdr.5 > $(MANDIR)/man5/vdr.5.gz
-+ @if [ ! -d $(VIDEODIR) ]; then\
-+ mkdir -p $(VIDEODIR);\
-+ cp *.conf $(VIDEODIR);\
-+ fi
-+
-+# Source documentation:
-+
-+srcdoc:
-+ @cp $(DOXYFILE) $(DOXYFILE).tmp
-+ @echo PROJECT_NUMBER = $(VDRVERSION) >> $(DOXYFILE).tmp
-+ $(DOXYGEN) $(DOXYFILE).tmp
-+ @rm $(DOXYFILE).tmp
-+
-+# Housekeeping:
-+
-+clean:
-+ $(MAKE) -C $(LSIDIR) clean
-+ -rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core* *~
-+ -rm -rf include
-+ -rm -rf srcdoc
-+fontclean:
-+ -rm -f fontfix*.c fontosd*.c fontsml*.c
-+CLEAN: clean fontclean
-+
diff -urNad vdr-1.3.31/recorder.c /tmp/dpep.cLVvp8/vdr-1.3.31/recorder.c
--- vdr-1.3.31/recorder.c 2005-08-31 21:03:49.369155368 +0200
+++ /tmp/dpep.cLVvp8/vdr-1.3.31/recorder.c 2005-08-31 21:04:17.154931288 +0200
@@ -424,1321 +200,6 @@
if (r < 0)
LOG_ERROR;
return r;
-diff -urNad vdr-1.3.31/recording.c.orig /tmp/dpep.cLVvp8/vdr-1.3.31/recording.c.orig
---- vdr-1.3.31/recording.c.orig 1970-01-01 01:00:00.000000000 +0100
-+++ /tmp/dpep.cLVvp8/vdr-1.3.31/recording.c.orig 2005-08-31 21:03:49.532130000 +0200
-@@ -0,0 +1,1311 @@
-+/*
-+ * recording.c: Recording file handling
-+ *
-+ * See the main source file 'vdr.c' for copyright information and
-+ * how to reach the author.
-+ *
-+ * $Id: recording.c 1.111 2005/08/13 14:00:48 kls Exp $
-+ */
-+
-+#include "recording.h"
-+#include <dirent.h>
-+#include <errno.h>
-+#include <fcntl.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <sys/stat.h>
-+#include <unistd.h>
-+#include "channels.h"
-+#include "i18n.h"
-+#include "interface.h"
-+#include "remux.h" //XXX+ I_FRAME
-+#include "skins.h"
-+#include "tools.h"
-+#include "videodir.h"
-+
-+#define SUMMARYFALLBACK
-+
-+#define RECEXT ".rec"
-+#define DELEXT ".del"
-+/* This was the original code, which works fine in a Linux only environment.
-+ Unfortunately, because of Windows and its brain dead file system, we have
-+ to use a more complicated approach, in order to allow users who have enabled
-+ the VFAT compile time option to see their recordings even if they forget to
-+ enable VFAT when compiling a new version of VDR... Gee, do I hate Windows.
-+ (kls 2002-07-27)
-+#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT
-+#define NAMEFORMAT "%s/%s/" DATAFORMAT
-+*/
-+// start of implementation for brain dead systems
-+#define DATAFORMAT "%4d-%02d-%02d.%02d%*c%02d.%02d.%02d" RECEXT
-+#ifdef VFAT
-+#define nameFORMAT "%4d-%02d-%02d.%02d.%02d.%02d.%02d" RECEXT
-+#else
-+#define nameFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT
-+#endif
-+#define NAMEFORMAT "%s/%s/" nameFORMAT
-+// end of implementation for brain dead systems
-+
-+#define RESUMEFILESUFFIX "/resume%s%s.vdr"
-+#ifdef SUMMARYFALLBACK
-+#define SUMMARYFILESUFFIX "/summary.vdr"
-+#endif
-+#define INFOFILESUFFIX "/info.vdr"
-+#define MARKSFILESUFFIX "/marks.vdr"
-+
-+#define MINDISKSPACE 1024 // MB
-+
-+#define DELETEDLIFETIME 1 // hours after which a deleted recording will be actually removed
-+#define REMOVECHECKDELTA 3600 // seconds between checks for removing deleted files
-+#define DISKCHECKDELTA 100 // seconds between checks for free disk space
-+#define REMOVELATENCY 10 // seconds to wait until next check after removing a file
-+
-+#define TIMERMACRO_TITLE "TITLE"
-+#define TIMERMACRO_EPISODE "EPISODE"
-+
-+#define MAX_SUBTITLE_LENGTH 40
-+
-+void RemoveDeletedRecordings(void)
-+{
-+ static time_t LastRemoveCheck = 0;
-+ if (time(NULL) - LastRemoveCheck > REMOVECHECKDELTA) {
-+ // Make sure only one instance of VDR does this:
-+ cLockFile LockFile(VideoDirectory);
-+ if (!LockFile.Lock())
-+ return;
-+ // Remove the oldest file that has been "deleted":
-+ cRecordings DeletedRecordings(true);
-+ if (DeletedRecordings.Load()) {
-+ cRecording *r = DeletedRecordings.First();
-+ cRecording *r0 = r;
-+ while (r) {
-+ if (r->start < r0->start)
-+ r0 = r;
-+ r = DeletedRecordings.Next(r);
-+ }
-+ if (r0 && time(NULL) - r0->start > DELETEDLIFETIME * 3600) {
-+ r0->Remove();
-+ RemoveEmptyVideoDirectories();
-+ LastRemoveCheck += REMOVELATENCY;
-+ return;
-+ }
-+ }
-+ LastRemoveCheck = time(NULL);
-+ }
-+}
-+
-+void AssertFreeDiskSpace(int Priority)
-+{
-+ // With every call to this function we try to actually remove
-+ // a file, or mark a file for removal ("delete" it), so that
-+ // it will get removed during the next call.
-+ static time_t LastFreeDiskCheck = 0;
-+ int Factor = (Priority == -1) ? 10 : 1;
-+ if (time(NULL) - LastFreeDiskCheck > DISKCHECKDELTA / Factor) {
-+ if (!VideoFileSpaceAvailable(MINDISKSPACE)) {
-+ // Make sure only one instance of VDR does this:
-+ cLockFile LockFile(VideoDirectory);
-+ if (!LockFile.Lock())
-+ return;
-+ // Remove the oldest file that has been "deleted":
-+ isyslog("low disk space while recording, trying to remove a deleted recording...");
-+ cRecordings DeletedRecordings(true);
-+ if (DeletedRecordings.Load()) {
-+ cRecording *r = DeletedRecordings.First();
-+ cRecording *r0 = r;
-+ while (r) {
-+ if (r->start < r0->start)
-+ r0 = r;
-+ r = DeletedRecordings.Next(r);
-+ }
-+ if (r0 && r0->Remove()) {
-+ LastFreeDiskCheck += REMOVELATENCY / Factor;
-+ return;
-+ }
-+ }
-+ // No "deleted" files to remove, so let's see if we can delete a recording:
-+ isyslog("...no deleted recording found, trying to delete an old recording...");
-+ if (Recordings.Load()) {
-+ cRecording *r = Recordings.First();
-+ cRecording *r0 = NULL;
-+ while (r) {
-+ if (!r->IsEdited() && r->lifetime < MAXLIFETIME) { // edited recordings and recordings with MAXLIFETIME live forever
-+ if ((r->lifetime == 0 && Priority > r->priority) || // the recording has no guaranteed lifetime and the new recording has higher priority
-+ (r->lifetime > 0 && (time(NULL) - r->start) / SECSINDAY >= r->lifetime)) { // the recording's guaranteed lifetime has expired
-+ if (r0) {
-+ if (r->priority < r0->priority || (r->priority == r0->priority && r->start < r0->start))
-+ r0 = r; // in any case we delete the one with the lowest priority (or the older one in case of equal priorities)
-+ }
-+ else
-+ r0 = r;
-+ }
-+ }
-+ r = Recordings.Next(r);
-+ }
-+ if (r0 && r0->Delete()) {
-+ Recordings.Del(r0);
-+ return;
-+ }
-+ }
-+ // Unable to free disk space, but there's nothing we can do about that...
-+ isyslog("...no old recording found, giving up");
-+ Interface->Confirm(tr("Low disk space!"), 30);
-+ }
-+ LastFreeDiskCheck = time(NULL);
-+ }
-+}
-+
-+// --- cResumeFile ------------------------------------------------------------
-+
-+cResumeFile::cResumeFile(const char *FileName)
-+{
-+ fileName = MALLOC(char, strlen(FileName) + strlen(RESUMEFILESUFFIX) + 1);
-+ if (fileName) {
-+ strcpy(fileName, FileName);
-+ sprintf(fileName + strlen(fileName), RESUMEFILESUFFIX, Setup.ResumeID ? "." : "", Setup.ResumeID ? *itoa(Setup.ResumeID) : "");
-+ }
-+ else
-+ esyslog("ERROR: can't allocate memory for resume file name");
-+}
-+
-+cResumeFile::~cResumeFile()
-+{
-+ free(fileName);
-+}
-+
-+int cResumeFile::Read(void)
-+{
-+ int resume = -1;
-+ if (fileName) {
-+ struct stat st;
-+ if (stat(fileName, &st) == 0) {
-+ if ((st.st_mode & S_IWUSR) == 0) // no write access, assume no resume
-+ return -1;
-+ }
-+ int f = open(fileName, O_RDONLY);
-+ if (f >= 0) {
-+ if (safe_read(f, &resume, sizeof(resume)) != sizeof(resume)) {
-+ resume = -1;
-+ LOG_ERROR_STR(fileName);
-+ }
-+ close(f);
-+ }
-+ else if (errno != ENOENT)
-+ LOG_ERROR_STR(fileName);
-+ }
-+ return resume;
-+}
-+
-+bool cResumeFile::Save(int Index)
-+{
-+ if (fileName) {
-+ int f = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE);
-+ if (f >= 0) {
-+ if (safe_write(f, &Index, sizeof(Index)) < 0)
-+ LOG_ERROR_STR(fileName);
-+ close(f);
-+ Recordings.ResetResume(fileName);
-+ return true;
-+ }
-+ }
-+ return false;
-+}
-+
-+void cResumeFile::Delete(void)
-+{
-+ if (fileName) {
-+ if (remove(fileName) < 0 && errno != ENOENT)
-+ LOG_ERROR_STR(fileName);
-+ Recordings.ResetResume(fileName);
-+ }
-+}
-+
-+// --- cRecordingInfo --------------------------------------------------------
-+
-+cRecordingInfo::cRecordingInfo(tChannelID ChannelID, const cEvent *Event)
-+{
-+ channelID = ChannelID;
-+ if (Event) {
-+ event = Event;
-+ ownEvent = NULL;
-+ }
-+ else
-+ event = ownEvent = new cEvent(0);
-+}
-+
-+cRecordingInfo::~cRecordingInfo()
-+{
-+ delete ownEvent;
-+}
-+
-+void cRecordingInfo::SetData(const char *Title, const char *ShortText, const char *Description)
-+{
-+ if (!isempty(Title))
-+ ((cEvent *)event)->SetTitle(Title);
-+ if (!isempty(ShortText))
-+ ((cEvent *)event)->SetShortText(ShortText);
-+ if (!isempty(Description))
-+ ((cEvent *)event)->SetDescription(Description);
-+}
-+
-+bool cRecordingInfo::Read(FILE *f)
-+{
-+ if (ownEvent) {
-+ cReadLine ReadLine;
-+ char *s;
-+ while ((s = ReadLine.Read(f)) != NULL) {
-+ char *t = skipspace(s + 1);
-+ switch (*s) {
-+ case 'C': {
-+ char *p = strchr(t, ' ');
-+ if (p)
-+ *p = 0; // strips optional channel name
-+ if (*t)
-+ channelID = tChannelID::FromString(t);
-+ }
-+ break;
-+ default: if (!ownEvent->Parse(s))
-+ return false;
-+ break;
-+ }
-+ }
-+ return true;
-+ }
-+ return false;
-+}
-+
-+bool cRecordingInfo::Write(FILE *f, const char *Prefix) const
-+{
-+ if (channelID.Valid())
-+ fprintf(f, "%sC %s\n", Prefix, *channelID.ToString());
-+ event->Dump(f, Prefix, true);
-+ return true;
-+}
-+
-+// --- cRecording ------------------------------------------------------------
-+
-+#define RESUME_NOT_INITIALIZED (-2)
-+
-+struct tCharExchange { char a; char b; };
-+tCharExchange CharExchange[] = {
-+ { '~', '/' },
-+ { ' ', '_' },
-+ { '\'', '\x01' },
-+ { '/', '\x02' },
-+ { 0, 0 }
-+ };
-+
-+static char *ExchangeChars(char *s, bool ToFileSystem)
-+{
-+ char *p = s;
-+ while (*p) {
-+#ifdef VFAT
-+ // The VFAT file system can't handle all characters, so we
-+ // have to take extra efforts to encode/decode them:
-+ if (ToFileSystem) {
-+ switch (*p) {
-+ // characters that can be used "as is":
-+ case '!':
-+ case '@':
-+ case '$':
-+ case '%':
-+ case '&':
-+ case '(':
-+ case ')':
-+ case '+':
-+ case ',':
-+ case '-':
-+ case ';':
-+ case '=':
-+ case '0' ... '9':
-+ case 'a' ... 'z':
-+ case 'A' ... 'Z':
-+ case 'ä': case 'Ä':
-+ case 'ö': case 'Ö':
-+ case 'ü': case 'Ü':
-+ case 'ß':
-+ break;
-+ // characters that can be mapped to other characters:
-+ case ' ': *p = '_'; break;
-+ case '~': *p = '/'; break;
-+ // characters that have to be encoded:
-+ default:
-+ if (*p != '.' || !*(p + 1) || *(p + 1) == '~') { // Windows can't handle '.' at the end of directory names
-+ int l = p - s;
-+ s = (char *)realloc(s, strlen(s) + 10);
-+ p = s + l;
-+ char buf[4];
-+ sprintf(buf, "#%02X", (unsigned char)*p);
-+ memmove(p + 2, p, strlen(p) + 1);
-+ strncpy(p, buf, 3);
-+ p += 2;
-+ }
-+ }
-+ }
-+ else {
-+ switch (*p) {
-+ // mapped characters:
-+ case '_': *p = ' '; break;
-+ case '/': *p = '~'; break;
-+ // encodes characters:
-+ case '#': {
-+ if (strlen(p) > 2) {
-+ char buf[3];
-+ sprintf(buf, "%c%c", *(p + 1), *(p + 2));
-+ unsigned char c = strtol(buf, NULL, 16);
-+ *p = c;
-+ memmove(p + 1, p + 3, strlen(p) - 2);
-+ }
-+ }
-+ break;
-+ // backwards compatibility:
-+ case '\x01': *p = '\''; break;
-+ case '\x02': *p = '/'; break;
-+ case '\x03': *p = ':'; break;
-+ }
-+ }
-+#else
-+ for (struct tCharExchange *ce = CharExchange; ce->a && ce->b; ce++) {
-+ if (*p == (ToFileSystem ? ce->a : ce->b)) {
-+ *p = ToFileSystem ? ce->b : ce->a;
-+ break;
-+ }
-+ }
-+#endif
-+ p++;
-+ }
-+ return s;
-+}
-+
-+cRecording::cRecording(cTimer *Timer, const cEvent *Event)
-+{
-+ resume = RESUME_NOT_INITIALIZED;
-+ titleBuffer = NULL;
-+ sortBuffer = NULL;
-+ fileName = NULL;
-+ name = NULL;
-+ // set up the actual name:
-+ const char *Title = Event ? Event->Title() : NULL;
-+ const char *Subtitle = Event ? Event->ShortText() : NULL;
-+ char SubtitleBuffer[MAX_SUBTITLE_LENGTH];
-+ if (isempty(Title))
-+ Title = Timer->Channel()->Name();
-+ if (isempty(Subtitle))
-+ Subtitle = " ";
-+ else if (strlen(Subtitle) > MAX_SUBTITLE_LENGTH) {
-+ // let's make sure the Subtitle doesn't produce too long a file name:
-+ strn0cpy(SubtitleBuffer, Subtitle, MAX_SUBTITLE_LENGTH);
-+ Subtitle = SubtitleBuffer;
-+ }
-+ char *macroTITLE = strstr(Timer->File(), TIMERMACRO_TITLE);
-+ char *macroEPISODE = strstr(Timer->File(), TIMERMACRO_EPISODE);
-+ if (macroTITLE || macroEPISODE) {
-+ name = strdup(Timer->File());
-+ name = strreplace(name, TIMERMACRO_TITLE, Title);
-+ name = strreplace(name, TIMERMACRO_EPISODE, Subtitle);
-+ // avoid blanks at the end:
-+ int l = strlen(name);
-+ while (l-- > 2) {
-+ if (name[l] == ' ' && name[l - 1] != '~')
-+ name[l] = 0;
-+ else
-+ break;
-+ }
-+ if (Timer->IsSingleEvent()) {
-+ Timer->SetFile(name); // this was an instant recording, so let's set the actual data
-+ Timers.SetModified();
-+ }
-+ }
-+ else if (Timer->IsSingleEvent() || !Setup.UseSubtitle)
-+ name = strdup(Timer->File());
-+ else
-+ asprintf(&name, "%s~%s", Timer->File(), Subtitle);
-+ // substitute characters that would cause problems in file names:
-+ strreplace(name, '\n', ' ');
-+ start = Timer->StartTime();
-+ priority = Timer->Priority();
-+ lifetime = Timer->Lifetime();
-+ // handle info:
-+ info = new cRecordingInfo(Timer->Channel()->GetChannelID(), Event);
-+ // this is a somewhat ugly hack to get the 'summary' information from the
-+ // timer into the recording info, but it saves us from having to actually
-+ // copy the entire event data:
-+ if (!isempty(Timer->Summary()))
-+ info->SetData(isempty(info->Title()) ? Timer->File() : NULL, NULL, Timer->Summary());
-+}
-+
-+cRecording::cRecording(const char *FileName)
-+{
-+ resume = RESUME_NOT_INITIALIZED;
-+ titleBuffer = NULL;
-+ sortBuffer = NULL;
-+ fileName = strdup(FileName);
-+ FileName += strlen(VideoDirectory) + 1;
-+ char *p = strrchr(FileName, '/');
-+
-+ name = NULL;
-+ info = new cRecordingInfo;
-+ if (p) {
-+ time_t now = time(NULL);
-+ struct tm tm_r;
-+ struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't'
-+ t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
-+ if (7 == sscanf(p + 1, DATAFORMAT, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &priority, &lifetime)) {
-+ t.tm_year -= 1900;
-+ t.tm_mon--;
-+ t.tm_sec = 0;
-+ start = mktime(&t);
-+ name = MALLOC(char, p - FileName + 1);
-+ strncpy(name, FileName, p - FileName);
-+ name[p - FileName] = 0;
-+ name = ExchangeChars(name, false);
-+ }
-+ // read an optional info file:
-+ char *InfoFileName = NULL;
-+ asprintf(&InfoFileName, "%s%s", fileName, INFOFILESUFFIX);
-+ FILE *f = fopen(InfoFileName, "r");
-+ if (f) {
-+ info->Read(f);
-+ fclose(f);
-+ }
-+ else if (errno != ENOENT)
-+ LOG_ERROR_STR(InfoFileName);
-+ free(InfoFileName);
-+#ifdef SUMMARYFALLBACK
-+ // fall back to the old 'summary.vdr' if there was no 'info.vdr':
-+ if (isempty(info->Title())) {
-+ char *SummaryFileName = NULL;
-+ asprintf(&SummaryFileName, "%s%s", fileName, SUMMARYFILESUFFIX);
-+ FILE *f = fopen(SummaryFileName, "r");
-+ if (f) {
-+ int line = 0;
-+ char *data[3] = { NULL };
-+ cReadLine ReadLine;
-+ char *s;
-+ while ((s = ReadLine.Read(f)) != NULL) {
-+ if (*s || line > 1) {
-+ if (data[line]) {
-+ int len = strlen(s);
-+ len += strlen(data[line]) + 1;
-+ data[line] = (char *)realloc(data[line], len + 1);
-+ strcat(data[line], "\n");
-+ strcat(data[line], s);
-+ }
-+ else
-+ data[line] = strdup(s);
-+ }
-+ else
-+ line++;
-+ }
-+ fclose(f);
-+ if (line == 1) {
-+ data[2] = data[1];
-+ data[1] = NULL;
-+ }
-+ info->SetData(data[0], data[1], data[2]);
-+ for (int i = 0; i < 3; i ++)
-+ free(data[i]);
-+ }
-+ else if (errno != ENOENT)
-+ LOG_ERROR_STR(SummaryFileName);
-+ free(SummaryFileName);
-+ }
-+#endif
-+ }
-+}
-+
-+cRecording::~cRecording()
-+{
-+ free(titleBuffer);
-+ free(sortBuffer);
-+ free(fileName);
-+ free(name);
-+ delete info;
-+}
-+
-+char *cRecording::StripEpisodeName(char *s)
-+{
-+ char *t = s, *s1 = NULL, *s2 = NULL;
-+ while (*t) {
-+ if (*t == '/') {
-+ if (s1) {
-+ if (s2)
-+ s1 = s2;
-+ s2 = t;
-+ }
-+ else
-+ s1 = t;
-+ }
-+ t++;
-+ } *s1 = 255;
-+ if (s1 && s2 && s1 != s && !strchr(".-$ª", *(s1 - 1)))
-+ memmove(s1 + 1, s2, t - s2 + 1);
-+ return s;
-+}
-+
-+char *cRecording::SortName(void) const
-+{
-+ if (!sortBuffer) {
-+ char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory) ));
-+ int l = strxfrm(NULL, s, 0) + 1;
-+ sortBuffer = MALLOC(char, l);
-+ strxfrm(sortBuffer, s, l);
-+ free(s);
-+ }
-+ return sortBuffer;
-+}
-+
-+int cRecording::GetResume(void) const
-+{
-+ if (resume == RESUME_NOT_INITIALIZED) {
-+ cResumeFile ResumeFile(FileName());
-+ resume = ResumeFile.Read();
-+ }
-+ return resume;
-+}
-+
-+int cRecording::Compare(const cListObject &ListObject) const
-+{
-+ cRecording *r = (cRecording *)&ListObject;
-+ return strcasecmp(SortName(), r->SortName());
-+}
-+
-+const char *cRecording::FileName(void) const
-+{
-+ if (!fileName) {
-+ struct tm tm_r;
-+ struct tm *t = localtime_r(&start, &tm_r);
-+ name = ExchangeChars(name, true);
-+ asprintf(&fileName, NAMEFORMAT, VideoDirectory, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, priority, lifetime);
-+ name = ExchangeChars(name, false);
-+ }
-+ return fileName;
-+}
-+
-+const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) const
-+{
-+ char New = NewIndicator && IsNew() ? '*' : ' ';
-+ free(titleBuffer);
-+ titleBuffer = NULL;
-+ if (Level < 0 || Level == HierarchyLevels()) {
-+ struct tm tm_r;
-+ struct tm *t = localtime_r(&start, &tm_r);
-+ char *s;
-+ if (Level > 0 && (s = strrchr(name, '~')) != NULL)
-+ s++;
-+ else
-+ s = name;
-+ asprintf(&titleBuffer, "%02d.%02d.%02d%c%02d:%02d%c%c%s",
-+ t->tm_mday,
-+ t->tm_mon + 1,
-+ t->tm_year % 100,
-+ Delimiter,
-+ t->tm_hour,
-+ t->tm_min,
-+ New,
-+ Delimiter,
-+ s);
-+ // let's not display a trailing '~':
-+ if (!NewIndicator)
-+ stripspace(titleBuffer);
-+ s = &titleBuffer[strlen(titleBuffer) - 1];
-+ if (*s == '~')
-+ *s = 0;
-+ }
-+ else if (Level < HierarchyLevels()) {
-+ const char *s = name;
-+ const char *p = s;
-+ while (*++s) {
-+ if (*s == '~') {
-+ if (Level--)
-+ p = s + 1;
-+ else
-+ break;
-+ }
-+ }
-+ titleBuffer = MALLOC(char, s - p + 3);
-+ *titleBuffer = Delimiter;
-+ *(titleBuffer + 1) = Delimiter;
-+ strn0cpy(titleBuffer + 2, p, s - p + 1);
-+ }
-+ else
-+ return "";
-+ return titleBuffer;
-+}
-+
-+const char *cRecording::PrefixFileName(char Prefix)
-+{
-+ cString p = PrefixVideoFileName(FileName(), Prefix);
-+ if (*p) {
-+ free(fileName);
-+ fileName = strdup(p);
-+ return fileName;
-+ }
-+ return NULL;
-+}
-+
-+int cRecording::HierarchyLevels(void) const
-+{
-+ const char *s = name;
-+ int level = 0;
-+ while (*++s) {
-+ if (*s == '~')
-+ level++;
-+ }
-+ return level;
-+}
-+
-+bool cRecording::IsEdited(void) const
-+{
-+ const char *s = strrchr(name, '~');
-+ s = !s ? name : s + 1;
-+ return *s == '%';
-+}
-+
-+bool cRecording::WriteInfo(void)
-+{
-+ char *InfoFileName = NULL;
-+ asprintf(&InfoFileName, "%s%s", fileName, INFOFILESUFFIX);
-+ FILE *f = fopen(InfoFileName, "w");
-+ if (f) {
-+ info->Write(f);
-+ fclose(f);
-+ }
-+ else
-+ LOG_ERROR_STR(InfoFileName);
-+ free(InfoFileName);
-+ return true;
-+}
-+
-+bool cRecording::Delete(void)
-+{
-+ bool result = true;
-+ char *NewName = strdup(FileName());
-+ char *ext = strrchr(NewName, '.');
-+ if (strcmp(ext, RECEXT) == 0) {
-+ strncpy(ext, DELEXT, strlen(ext));
-+ if (access(NewName, F_OK) == 0) {
-+ // the new name already exists, so let's remove that one first:
-+ isyslog("removing recording %s", NewName);
-+ RemoveVideoFile(NewName);
-+ }
-+ isyslog("deleting recording %s", FileName());
-+ result = RenameVideoFile(FileName(), NewName);
-+ }
-+ free(NewName);
-+ return result;
-+}
-+
-+bool cRecording::Remove(void)
-+{
-+ // let's do a final safety check here:
-+ if (!endswith(FileName(), DELEXT)) {
-+ esyslog("attempt to remove recording %s", FileName());
-+ return false;
-+ }
-+ isyslog("removing recording %s", FileName());
-+ return RemoveVideoFile(FileName());
-+}
-+
-+void cRecording::ResetResume(void) const
-+{
-+ resume = RESUME_NOT_INITIALIZED;
-+}
-+
-+// --- cRecordings -----------------------------------------------------------
-+
-+cRecordings Recordings;
-+
-+cRecordings::cRecordings(bool Deleted)
-+{
-+ deleted = Deleted;
-+ lastUpdate = 0;
-+}
-+
-+void cRecordings::ScanVideoDir(const char *DirName)
-+{
-+ cReadDir d(DirName);
-+ struct dirent *e;
-+ while ((e = d.Next()) != NULL) {
-+ if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) {
-+ char *buffer;
-+ asprintf(&buffer, "%s/%s", DirName, e->d_name);
-+ struct stat st;
-+ if (stat(buffer, &st) == 0) {
-+ if (S_ISLNK(st.st_mode)) {
-+ char *old = buffer;
-+ buffer = ReadLink(old);
-+ free(old);
-+ if (!buffer)
-+ continue;
-+ if (stat(buffer, &st) != 0) {
-+ free(buffer);
-+ continue;
-+ }
-+ }
-+ if (S_ISDIR(st.st_mode)) {
-+ if (endswith(buffer, deleted ? DELEXT : RECEXT)) {
-+ cRecording *r = new cRecording(buffer);
-+ if (r->Name())
-+ Add(r);
-+ else
-+ delete r;
-+ }
-+ else
-+ ScanVideoDir(buffer);
-+ }
-+ }
-+ free(buffer);
-+ }
-+ }
-+}
-+
-+bool cRecordings::NeedsUpdate(void)
-+{
-+ return lastUpdate <= LastModifiedTime(AddDirectory(VideoDirectory, ".update"));
-+}
-+
-+bool cRecordings::Load(void)
-+{
-+ lastUpdate = time(NULL); // doing this first to make sure we don't miss anything
-+ Clear();
-+ ScanVideoDir(VideoDirectory);
-+ Sort();
-+ return Count() > 0;
-+}
-+
-+cRecording *cRecordings::GetByName(const char *FileName)
-+{
-+ for (cRecording *recording = First(); recording; recording = Next(recording)) {
-+ if (strcmp(recording->FileName(), FileName) == 0)
-+ return recording;
-+ }
-+ return NULL;
-+}
-+
-+void cRecordings::AddByName(const char *FileName)
-+{
-+ cRecording *recording = GetByName(FileName);
-+ if (!recording) {
-+ recording = new cRecording(FileName);
-+ Add(recording);
-+ }
-+}
-+
-+void cRecordings::DelByName(const char *FileName)
-+{
-+ cRecording *recording = GetByName(FileName);
-+ if (recording)
-+ Del(recording);
-+}
-+
-+void cRecordings::ResetResume(const char *ResumeFileName)
-+{
-+ for (cRecording *recording = First(); recording; recording = Next(recording))
-+ if (!ResumeFileName || strncmp(ResumeFileName, recording->FileName(), strlen(recording->FileName())) == 0)
-+ recording->ResetResume();
-+}
-+
-+// --- cMark -----------------------------------------------------------------
-+
-+cMark::cMark(int Position, const char *Comment)
-+{
-+ position = Position;
-+ comment = Comment ? strdup(Comment) : NULL;
-+}
-+
-+cMark::~cMark()
-+{
-+ free(comment);
-+}
-+
-+cString cMark::ToText(void)
-+{
-+ char *buffer;
-+ asprintf(&buffer, "%s%s%s\n", *IndexToHMSF(position, true), comment ? " " : "", comment ? comment : "");
-+ return cString(buffer, true);
-+}
-+
-+bool cMark::Parse(const char *s)
-+{
-+ free(comment);
-+ comment = NULL;
-+ position = HMSFToIndex(s);
-+ const char *p = strchr(s, ' ');
-+ if (p) {
-+ p = skipspace(p);
-+ if (*p)
-+ comment = strdup(p);
-+ }
-+ return true;
-+}
-+
-+bool cMark::Save(FILE *f)
-+{
-+ return fprintf(f, ToText()) > 0;
-+}
-+
-+// --- cMarks ----------------------------------------------------------------
-+
-+bool cMarks::Load(const char *RecordingFileName)
-+{
-+ if (cConfig<cMark>::Load(AddDirectory(RecordingFileName, MARKSFILESUFFIX))) {
-+ Sort();
-+ return true;
-+ }
-+ return false;
-+}
-+
-+void cMarks::Sort(void)
-+{
-+ for (cMark *m1 = First(); m1; m1 = Next(m1)) {
-+ for (cMark *m2 = Next(m1); m2; m2 = Next(m2)) {
-+ if (m2->position < m1->position) {
-+ swap(m1->position, m2->position);
-+ swap(m1->comment, m2->comment);
-+ }
-+ }
-+ }
-+}
-+
-+cMark *cMarks::Add(int Position)
-+{
-+ cMark *m = Get(Position);
-+ if (!m) {
-+ cConfig<cMark>::Add(m = new cMark(Position));
-+ Sort();
-+ }
-+ return m;
-+}
-+
-+cMark *cMarks::Get(int Position)
-+{
-+ for (cMark *mi = First(); mi; mi = Next(mi)) {
-+ if (mi->position == Position)
-+ return mi;
-+ }
-+ return NULL;
-+}
-+
-+cMark *cMarks::GetPrev(int Position)
-+{
-+ for (cMark *mi = Last(); mi; mi = Prev(mi)) {
-+ if (mi->position < Position)
-+ return mi;
-+ }
-+ return NULL;
-+}
-+
-+cMark *cMarks::GetNext(int Position)
-+{
-+ for (cMark *mi = First(); mi; mi = Next(mi)) {
-+ if (mi->position > Position)
-+ return mi;
-+ }
-+ return NULL;
-+}
-+
-+// --- cRecordingUserCommand -------------------------------------------------
-+
-+const char *cRecordingUserCommand::command = NULL;
-+
-+void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName)
-+{
-+ if (command) {
-+ char *cmd;
-+ asprintf(&cmd, "%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\"$"));
-+ isyslog("executing '%s'", cmd);
-+ SystemExec(cmd);
-+ free(cmd);
-+ }
-+}
-+
-+// --- XXX+
-+
-+//XXX+ somewhere else???
-+// --- cIndexFile ------------------------------------------------------------
-+
-+#define INDEXFILESUFFIX "/index.vdr"
-+
-+// The number of frames to stay off the end in case of time shift:
-+#define INDEXSAFETYLIMIT 150 // frames
-+
-+// The maximum time to wait before giving up while catching up on an index file:
-+#define MAXINDEXCATCHUP 8 // seconds
-+
-+// The minimum age of an index file for considering it no longer to be written:
-+#define MININDEXAGE 3600 // seconds
-+
-+cIndexFile::cIndexFile(const char *FileName, bool Record)
-+:resumeFile(FileName)
-+{
-+ f = -1;
-+ fileName = NULL;
-+ size = 0;
-+ last = -1;
-+ index = NULL;
-+ if (FileName) {
-+ fileName = MALLOC(char, strlen(FileName) + strlen(INDEXFILESUFFIX) + 1);
-+ if (fileName) {
-+ strcpy(fileName, FileName);
-+ char *pFileExt = fileName + strlen(fileName);
-+ strcpy(pFileExt, INDEXFILESUFFIX);
-+ int delta = 0;
-+ if (access(fileName, R_OK) == 0) {
-+ struct stat buf;
-+ if (stat(fileName, &buf) == 0) {
-+ delta = buf.st_size % sizeof(tIndex);
-+ if (delta) {
-+ delta = sizeof(tIndex) - delta;
-+ esyslog("ERROR: invalid file size (%ld) in '%s'", buf.st_size, fileName);
-+ }
-+ last = (buf.st_size + delta) / sizeof(tIndex) - 1;
-+ if (!Record && last >= 0) {
-+ size = last + 1;
-+ index = MALLOC(tIndex, size);
-+ if (index) {
-+ f = open(fileName, O_RDONLY);
-+ if (f >= 0) {
-+ if ((int)safe_read(f, index, buf.st_size) != buf.st_size) {
-+ esyslog("ERROR: can't read from file '%s'", fileName);
-+ free(index);
-+ index = NULL;
-+ close(f);
-+ f = -1;
-+ }
-+ // we don't close f here, see CatchUp()!
-+ }
-+ else
-+ LOG_ERROR_STR(fileName);
-+ }
-+ else
-+ esyslog("ERROR: can't allocate %d bytes for index '%s'", size * sizeof(tIndex), fileName);
-+ }
-+ }
-+ else
-+ LOG_ERROR;
-+ }
-+ else if (!Record)
-+ isyslog("missing index file %s", fileName);
-+ if (Record) {
-+ if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, DEFFILEMODE)) >= 0) {
-+ if (delta) {
-+ esyslog("ERROR: padding index file with %d '0' bytes", delta);
-+ while (delta--)
-+ writechar(f, 0);
-+ }
-+ }
-+ else
-+ LOG_ERROR_STR(fileName);
-+ }
-+ }
-+ else
-+ esyslog("ERROR: can't copy file name '%s'", FileName);
-+ }
-+}
-+
-+cIndexFile::~cIndexFile()
-+{
-+ if (f >= 0)
-+ close(f);
-+ free(fileName);
-+ free(index);
-+}
-+
-+bool cIndexFile::CatchUp(int Index)
-+{
-+ // returns true unless something really goes wrong, so that 'index' becomes NULL
-+ if (index && f >= 0) {
-+ cMutexLock MutexLock(&mutex);
-+ for (int i = 0; i <= MAXINDEXCATCHUP && (Index < 0 || Index >= last); i++) {
-+ struct stat buf;
-+ if (fstat(f, &buf) == 0) {
-+ if (time(NULL) - buf.st_mtime > MININDEXAGE) {
-+ // apparently the index file is not being written any more
-+ close(f);
-+ f = -1;
-+ break;
-+ }
-+ int newLast = buf.st_size / sizeof(tIndex) - 1;
-+ if (newLast > last) {
-+ if (size <= newLast) {
-+ size *= 2;
-+ if (size <= newLast)
-+ size = newLast + 1;
-+ }
-+ index = (tIndex *)realloc(index, size * sizeof(tIndex));
-+ if (index) {
-+ int offset = (last + 1) * sizeof(tIndex);
-+ int delta = (newLast - last) * sizeof(tIndex);
-+ if (lseek(f, offset, SEEK_SET) == offset) {
-+ if (safe_read(f, &index[last + 1], delta) != delta) {
-+ esyslog("ERROR: can't read from index");
-+ free(index);
-+ index = NULL;
-+ close(f);
-+ f = -1;
-+ break;
-+ }
-+ last = newLast;
-+ }
-+ else
-+ LOG_ERROR_STR(fileName);
-+ }
-+ else
-+ esyslog("ERROR: can't realloc() index");
-+ }
-+ }
-+ else
-+ LOG_ERROR_STR(fileName);
-+ if (Index < last - (i ? 2 * INDEXSAFETYLIMIT : 0) || Index > 10 * INDEXSAFETYLIMIT) // keep off the end in case of "Pause live video"
-+ break;
-+ cCondWait::SleepMs(1000);
-+ }
-+ }
-+ return index != NULL;
-+}
-+
-+bool cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset)
-+{
-+ if (f >= 0) {
-+ tIndex i = { FileOffset, PictureType, FileNumber, 0 };
-+ if (safe_write(f, &i, sizeof(i)) < 0) {
-+ LOG_ERROR_STR(fileName);
-+ close(f);
-+ f = -1;
-+ return false;
-+ }
-+ last++;
-+ }
-+ return f >= 0;
-+}
-+
-+bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType, int *Length)
-+{
-+ if (CatchUp(Index)) {
-+ if (Index >= 0 && Index < last) {
-+ *FileNumber = index[Index].number;
-+ *FileOffset = index[Index].offset;
-+ if (PictureType)
-+ *PictureType = index[Index].type;
-+ if (Length) {
-+ int fn = index[Index + 1].number;
-+ int fo = index[Index + 1].offset;
-+ if (fn == *FileNumber)
-+ *Length = fo - *FileOffset;
-+ else
-+ *Length = -1; // this means "everything up to EOF" (the buffer's Read function will act accordingly)
-+ }
-+ return true;
-+ }
-+ }
-+ return false;
-+}
-+
-+int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length, bool StayOffEnd)
-+{
-+ if (CatchUp()) {
-+ int d = Forward ? 1 : -1;
-+ for (;;) {
-+ Index += d;
-+ if (Index >= 0 && Index < last - ((Forward && StayOffEnd) ? INDEXSAFETYLIMIT : 0)) {
-+ if (index[Index].type == I_FRAME) {
-+ if (FileNumber)
-+ *FileNumber = index[Index].number;
-+ else
-+ FileNumber = &index[Index].number;
-+ if (FileOffset)
-+ *FileOffset = index[Index].offset;
-+ else
-+ FileOffset = &index[Index].offset;
-+ if (Length) {
-+ // all recordings end with a non-I_FRAME, so the following should be safe:
-+ int fn = index[Index + 1].number;
-+ int fo = index[Index + 1].offset;
-+ if (fn == *FileNumber)
-+ *Length = fo - *FileOffset;
-+ else {
-+ esyslog("ERROR: 'I' frame at end of file #%d", *FileNumber);
-+ *Length = -1;
-+ }
-+ }
-+ return Index;
-+ }
-+ }
-+ else
-+ break;
-+ }
-+ }
-+ return -1;
-+}
-+
-+int cIndexFile::Get(uchar FileNumber, int FileOffset)
-+{
-+ if (CatchUp()) {
-+ //TODO implement binary search!
-+ int i;
-+ for (i = 0; i < last; i++) {
-+ if (index[i].number > FileNumber || (index[i].number == FileNumber) && index[i].offset >= FileOffset)
-+ break;
-+ }
-+ return i;
-+ }
-+ return -1;
-+}
-+
-+// --- cFileName -------------------------------------------------------------
-+
-+#include <errno.h>
-+#include <unistd.h>
-+#include "videodir.h"
-+
-+#define MAXFILESPERRECORDING 255
-+#define RECORDFILESUFFIX "/%03d.vdr"
-+#define RECORDFILESUFFIXLEN 20 // some additional bytes for safety...
-+
-+cFileName::cFileName(const char *FileName, bool Record, bool Blocking)
-+{
-+ file = -1;
-+ fileNumber = 0;
-+ record = Record;
-+ blocking = Blocking;
-+ // Prepare the file name:
-+ fileName = MALLOC(char, strlen(FileName) + RECORDFILESUFFIXLEN);
-+ if (!fileName) {
-+ esyslog("ERROR: can't copy file name '%s'", fileName);
-+ return;
-+ }
-+ strcpy(fileName, FileName);
-+ pFileNumber = fileName + strlen(fileName);
-+ SetOffset(1);
-+}
-+
-+cFileName::~cFileName()
-+{
-+ Close();
-+ free(fileName);
-+}
-+
-+int cFileName::Open(void)
-+{
-+ if (file < 0) {
-+ int BlockingFlag = blocking ? 0 : O_NONBLOCK;
-+ if (record) {
-+ dsyslog("recording to '%s'", fileName);
-+ file = OpenVideoFile(fileName, O_RDWR | O_CREAT | BlockingFlag);
-+ if (file < 0)
-+ LOG_ERROR_STR(fileName);
-+ }
-+ else {
-+ if (access(fileName, R_OK) == 0) {
-+ dsyslog("playing '%s'", fileName);
-+ file = open(fileName, O_RDONLY | BlockingFlag);
-+ if (file < 0)
-+ LOG_ERROR_STR(fileName);
-+ }
-+ else if (errno != ENOENT)
-+ LOG_ERROR_STR(fileName);
-+ }
-+ }
-+ return file;
-+}
-+
-+void cFileName::Close(void)
-+{
-+ if (file >= 0) {
-+ if ((record && CloseVideoFile(file) < 0) || (!record && close(file) < 0))
-+ LOG_ERROR_STR(fileName);
-+ file = -1;
-+ }
-+}
-+
-+int cFileName::SetOffset(int Number, int Offset)
-+{
-+ if (fileNumber != Number)
-+ Close();
-+ if (0 < Number && Number <= MAXFILESPERRECORDING) {
-+ fileNumber = Number;
-+ sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber);
-+ if (record) {
-+ if (access(fileName, F_OK) == 0) {
-+ // files exists, check if it has non-zero size
-+ struct stat buf;
-+ if (stat(fileName, &buf) == 0) {
-+ if (buf.st_size != 0)
-+ return SetOffset(Number + 1); // file exists and has non zero size, let's try next suffix
-+ else {
-+ // zero size file, remove it
-+ dsyslog ("cFileName::SetOffset: removing zero-sized file %s\n", fileName);
-+ unlink (fileName);
-+ }
-+ }
-+ else
-+ return SetOffset(Number + 1); // error with fstat - should not happen, just to be on the safe side
-+ }
-+ else if (errno != ENOENT) { // something serious has happened
-+ LOG_ERROR_STR(fileName);
-+ return -1;
-+ }
-+ // found a non existing file suffix
-+ }
-+ if (Open() >= 0) {
-+ if (!record && Offset >= 0 && lseek(file, Offset, SEEK_SET) != Offset) {
-+ LOG_ERROR_STR(fileName);
-+ return -1;
-+ }
-+ }
-+ return file;
-+ }
-+ esyslog("ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING);
-+ return -1;
-+}
-+
-+int cFileName::NextFile(void)
-+{
-+ return SetOffset(fileNumber + 1);
-+}
-+
-+// --- Index stuff -----------------------------------------------------------
-+
-+cString IndexToHMSF(int Index, bool WithFrame)
-+{
-+ char buffer[16];
-+ int f = (Index % FRAMESPERSEC) + 1;
-+ int s = (Index / FRAMESPERSEC);
-+ int m = s / 60 % 60;
-+ int h = s / 3600;
-+ s %= 60;
-+ snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f);
-+ return buffer;
-+}
-+
-+int HMSFToIndex(const char *HMSF)
-+{
-+ int h, m, s, f = 0;
-+ if (3 <= sscanf(HMSF, "%d:%d:%d.%d", &h, &m, &s, &f))
-+ return (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1;
-+ return 0;
-+}
-+
-+int SecondsToFrames(int Seconds)
-+{
-+ return Seconds * FRAMESPERSEC;
-+}
-+
-+// --- ReadFrame -------------------------------------------------------------
-+
-+int ReadFrame(int f, uchar *b, int Length, int Max)
-+{
-+ if (Length == -1)
-+ Length = Max; // this means we read up to EOF (see cIndex)
-+ else if (Length > Max) {
-+ esyslog("ERROR: frame larger than buffer (%d > %d)", Length, Max);
-+ Length = Max;
-+ }
-+ int r = safe_read(f, b, Length);
-+ if (r < 0)
-+ LOG_ERROR;
-+ return r;
-+}
-+
-+
diff -urNad vdr-1.3.31/tools.c /tmp/dpep.cLVvp8/vdr-1.3.31/tools.c
--- vdr-1.3.31/tools.c 2005-08-27 16:43:55.000000000 +0200
+++ /tmp/dpep.cLVvp8/vdr-1.3.31/tools.c 2005-08-31 21:04:17.163929920 +0200
More information about the pkg-vdr-dvb-changes
mailing list