Made several functions threadsafe

This commit is contained in:
Klaus Schmidinger 2004-12-19 16:33:34 +01:00
parent 9a8ef2b6c2
commit 1d3495a0f0
18 changed files with 360 additions and 219 deletions

View File

@ -348,6 +348,8 @@ Rainer Zocholl <vdrcontrib@zocki.toppoint.de>
for suggesting that VDR should stop if one of the configuration files can't be
read correctly at program startup
for reporting a possible race condition in generating the DVB device names
for pointing out that non-threadsafe functions should be replaced with their
threadsafe versions
Oleg Assovski <assen@bitcom.msk.ru>
for adding EPG scanning for another 4 days

12
HISTORY
View File

@ -3209,3 +3209,15 @@ Video Disk Recorder Revision History
- Added 'channels.conf.terr' entries for Lübeck (thanks to Stefan Hußfeldt).
- Fixed a race condition in starting a thread (thanks to Reinhard Nissl for
reporting this one).
- Replaced non-threadsafe library functions with their threadsafe versions (thanks
to Rainer Zocholl for pointing this out).
- Other non-threadsafe functions have been replaced by threadsafe classes that hide
the actual buffering. In particular these are:
readdir() -> cReadDir
readline() -> cReadLine
strescape() -> cStrEscape
AddDirectory() -> cAddDirectory
ctime() -> cCtime
itoa() -> cItoa
WeekDayName() -> cWeekDayName
DayDateTime() -> cDayDateTime

View File

@ -8,3 +8,7 @@ VDR Plugin 'skincurses' Revision History
2004-05-31: Version 0.0.2
- Fixed some default parameters.
2004-12-26: Version 0.0.3
- Made several functions threadsafe.

View File

@ -32,3 +32,7 @@ VDR Plugin 'sky' Revision History
2004-12-12: Version 0.3.2
- Changed Apid access in cChannel.
2004-12-19: Version 0.3.3
- Made several functions threadsafe.

View File

@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
* $Id: sky.c 1.8 2004/12/12 14:27:33 kls Exp $
* $Id: sky.c 1.9 2004/12/19 15:33:47 kls Exp $
*/
#include <sys/socket.h>
@ -14,7 +14,7 @@
#include <vdr/plugin.h>
#include <vdr/sources.h>
static const char *VERSION = "0.3.2";
static const char *VERSION = "0.3.3";
static const char *DESCRIPTION = "Sky Digibox interface";
// --- cDigiboxDevice --------------------------------------------------------
@ -273,7 +273,7 @@ bool cPluginSky::Initialize(void)
// Initialize any background activities the plugin shall perform.
const char *ConfigDir = ConfigDirectory(Name());
if (ConfigDir) {
if (SkyChannels.Load(AddDirectory(ConfigDir, "channels.conf.sky"), true)) {
if (SkyChannels.Load(*cAddDirectory(ConfigDir, "channels.conf.sky"), true)) {
new cDigiboxDevice;
return true;
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: channels.c 1.31 2004/11/02 18:07:05 kls Exp $
* $Id: channels.c 1.32 2004/12/19 11:24:51 kls Exp $
*/
#include "channels.h"
@ -705,7 +705,8 @@ bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
p = apidbuf;
char *q;
int NumApids = 0;
while ((q = strtok(p, ",")) != NULL) {
char *strtok_next;
while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
if (NumApids < MAXAPIDS) {
char *l = strchr(q, '=');
if (l) {
@ -725,7 +726,8 @@ bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
char *p = dpidbuf;
char *q;
int NumDpids = 0;
while ((q = strtok(p, ",")) != NULL) {
char *strtok_next;
while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
if (NumDpids < MAXAPIDS) {
char *l = strchr(q, '=');
if (l) {
@ -747,7 +749,8 @@ bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
char *p = caidbuf;
char *q;
int NumCaIds = 0;
while ((q = strtok(p, ",")) != NULL) {
char *strtok_next;
while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
if (NumCaIds < MAXCAIDS) {
caids[NumCaIds++] = strtol(q, NULL, 16) & 0xFFFF;
if (NumCaIds == 1 && caids[0] <= 0x00FF)

5
keys.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: keys.c 1.5 2003/09/14 10:07:47 kls Exp $
* $Id: keys.c 1.6 2004/12/19 11:25:47 kls Exp $
*/
#include "keys.h"
@ -195,7 +195,8 @@ bool cKeyMacro::Parse(char *s)
{
int n = 0;
char *p;
while ((p = strtok(s, " \t")) != NULL) {
char *strtok_next;
while ((p = strtok_r(s, " \t", &strtok_next)) != NULL) {
if (n < MAXKEYSINMACRO) {
if (*p == '@') {
if (plugin) {

5
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osd.c 1.58 2004/10/16 10:31:34 kls Exp $
* $Id: osd.c 1.59 2004/12/19 12:27:38 kls Exp $
*/
#include "osd.h"
@ -197,7 +197,8 @@ bool cBitmap::LoadXpm(const char *FileName)
int lines = 0;
int index = 0;
char *s;
while ((s = readline(f)) != NULL) {
cReadLine ReadLine;
while ((s = ReadLine.Read(f)) != NULL) {
s = skipspace(s);
if (!isXpm) {
if (strcmp(s, "/* XPM */") != 0) {

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: plugin.c 1.11 2004/05/22 11:25:22 kls Exp $
* $Id: plugin.c 1.12 2004/12/19 12:05:28 kls Exp $
*/
#include "plugin.h"
@ -256,26 +256,23 @@ void cPluginManager::SetDirectory(const char *Directory)
void cPluginManager::AddPlugin(const char *Args)
{
if (strcmp(Args, "*") == 0) {
DIR *d = opendir(directory);
if (d) {
struct dirent *e;
while ((e = readdir(d)) != NULL) {
if (strstr(e->d_name, LIBVDR_PREFIX) == e->d_name) {
char *p = strstr(e->d_name, SO_INDICATOR);
if (p) {
*p = 0;
p += strlen(SO_INDICATOR);
if (strcmp(p, VDRVERSION) == 0) {
char *name = e->d_name + strlen(LIBVDR_PREFIX);
if (strcmp(name, "*") != 0) { // let's not get into a loop!
AddPlugin(e->d_name + strlen(LIBVDR_PREFIX));
}
cReadDir d(directory);
struct dirent *e;
while ((e = d.Next()) != NULL) {
if (strstr(e->d_name, LIBVDR_PREFIX) == e->d_name) {
char *p = strstr(e->d_name, SO_INDICATOR);
if (p) {
*p = 0;
p += strlen(SO_INDICATOR);
if (strcmp(p, VDRVERSION) == 0) {
char *name = e->d_name + strlen(LIBVDR_PREFIX);
if (strcmp(name, "*") != 0) { // let's not get into a loop!
AddPlugin(e->d_name + strlen(LIBVDR_PREFIX));
}
}
}
}
closedir(d);
}
}
return;
}
char *s = strdup(skipspace(Args));

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recording.c 1.92 2004/11/01 14:04:47 kls Exp $
* $Id: recording.c 1.93 2004/12/19 15:44:42 kls Exp $
*/
#include "recording.h"
@ -157,7 +157,7 @@ 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) : "");
sprintf(fileName + strlen(fileName), RESUMEFILESUFFIX, Setup.ResumeID ? "." : "", Setup.ResumeID ? *cItoa(Setup.ResumeID) : "");
}
else
esyslog("ERROR: can't allocate memory for resume file name");
@ -628,47 +628,44 @@ cRecordings::cRecordings(bool Deleted)
void cRecordings::ScanVideoDir(const char *DirName)
{
DIR *d = opendir(DirName);
if (d) {
struct dirent *e;
while ((e = readdir(d)) != 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)) {
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)) {
free(buffer);
buffer = ReadLink(buffer);
if (!buffer)
continue;
if (stat(buffer, &st) != 0) {
free(buffer);
buffer = ReadLink(buffer);
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);
continue;
}
}
free(buffer);
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);
}
closedir(d);
}
}
}
bool cRecordings::NeedsUpdate(void)
{
return lastUpdate <= LastModifiedTime(AddDirectory(VideoDirectory, ".update"));
return lastUpdate <= LastModifiedTime(*cAddDirectory(VideoDirectory, ".update"));
}
bool cRecordings::Load(void)
@ -750,8 +747,7 @@ bool cMark::Save(FILE *f)
bool cMarks::Load(const char *RecordingFileName)
{
const char *MarksFile = AddDirectory(RecordingFileName, MARKSFILESUFFIX);
if (cConfig<cMark>::Load(MarksFile)) {
if (cConfig<cMark>::Load(*cAddDirectory(RecordingFileName, MARKSFILESUFFIX))) {
Sort();
return true;
}
@ -815,7 +811,7 @@ void cRecordingUserCommand::InvokeCommand(const char *State, const char *Recordi
{
if (command) {
char *cmd;
asprintf(&cmd, "%s %s \"%s\"", command, State, strescape(RecordingFileName, "\"$"));
asprintf(&cmd, "%s %s \"%s\"", command, State, *cStrEscape(RecordingFileName, "\"$"));
isyslog("executing '%s'", cmd);
SystemExec(cmd);
free(cmd);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: skinclassic.c 1.7 2004/05/31 14:09:00 kls Exp $
* $Id: skinclassic.c 1.8 2004/12/19 15:46:09 kls Exp $
*/
#include "skinclassic.h"
@ -141,8 +141,8 @@ void cSkinClassicDisplayChannel::SetMessage(eMessageType Type, const char *Text)
void cSkinClassicDisplayChannel::Flush(void)
{
if (!message) {
const char *date = DayDateTime();
osd->DrawText(osd->Width() - cFont::GetFont(fontSml)->Width(date) - 2, 0, date, Theme.Color(clrChannelDate), Theme.Color(clrBackground), cFont::GetFont(fontSml));
cDayDateTime date;
osd->DrawText(osd->Width() - cFont::GetFont(fontSml)->Width(*date) - 2, 0, *date, Theme.Color(clrChannelDate), Theme.Color(clrBackground), cFont::GetFont(fontSml));
}
osd->Flush();
}
@ -338,9 +338,9 @@ void cSkinClassicDisplayMenu::SetText(const char *Text, bool FixedFont)
void cSkinClassicDisplayMenu::Flush(void)
{
const char *date = DayDateTime();
cDayDateTime date;
const cFont *font = cFont::GetFont(fontOsd);
osd->DrawText(x1 - font->Width(date) - 2, y0, date, Theme.Color(clrMenuDate), Theme.Color(clrMenuTitleBg), font);
osd->DrawText(x1 - font->Width(*date) - 2, y0, *date, Theme.Color(clrMenuDate), Theme.Color(clrMenuTitleBg), font);
osd->Flush();
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: skinsttng.c 1.7 2004/12/05 13:19:59 kls Exp $
* $Id: skinsttng.c 1.8 2004/12/19 15:48:55 kls Exp $
*/
// Star Trek: The Next Generation® is a registered trademark of Paramount Pictures
@ -289,9 +289,9 @@ void cSkinSTTNGDisplayChannel::Flush(void)
{
if (withInfo) {
if (!message) {
const char *date = DayDateTime();
cDayDateTime date;
const cFont *font = cFont::GetFont(fontSml);
osd->DrawText(x4 - font->Width(date) - 2, y7 - font->Height(date), date, Theme.Color(clrChannelDate), frameColor, font);
osd->DrawText(x4 - font->Width(*date) - 2, y7 - font->Height(*date), *date, Theme.Color(clrChannelDate), frameColor, font);
}
int seen = 0;
@ -456,11 +456,11 @@ void cSkinSTTNGDisplayMenu::SetTitle(const char *Title)
void cSkinSTTNGDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue)
{
const char *date = DayDateTime();
cDayDateTime date;
const cFont *font = cFont::GetFont(fontSml);
int d = 10;
int d2 = d / 2;
int t4 = x4 - font->Width(date) - 2;
int t4 = x4 - font->Width(*date) - 2;
int w = t4 - x3;
int t0 = x3 + d2;
int t1 = x3 + w / 4;
@ -583,9 +583,9 @@ void cSkinSTTNGDisplayMenu::SetText(const char *Text, bool FixedFont)
void cSkinSTTNGDisplayMenu::Flush(void)
{
if (!message) {
const char *date = DayDateTime();
cDayDateTime date;
const cFont *font = cFont::GetFont(fontSml);
osd->DrawText(x4 - font->Width(date) - 2, y7 - font->Height(date), date, Theme.Color(clrMenuDate), frameColor, font);
osd->DrawText(x4 - font->Width(*date) - 2, y7 - font->Height(*date), *date, Theme.Color(clrMenuDate), frameColor, font);
}
osd->Flush();
}

31
svdrp.c
View File

@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
* $Id: svdrp.c 1.65 2004/10/31 10:09:53 kls Exp $
* $Id: svdrp.c 1.66 2004/12/19 13:52:34 kls Exp $
*/
#include "svdrp.h"
@ -555,8 +555,9 @@ void cSVDRP::CmdGRAB(const char *Option)
char buf[strlen(Option) + 1];
char *p = strcpy(buf, Option);
const char *delim = " \t";
FileName = strtok(p, delim);
if ((p = strtok(NULL, delim)) != NULL) {
char *strtok_next;
FileName = strtok_r(p, delim, &strtok_next);
if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
if (strcasecmp(p, "JPEG") == 0)
Jpeg = true;
else if (strcasecmp(p, "PNM") == 0)
@ -566,7 +567,7 @@ void cSVDRP::CmdGRAB(const char *Option)
return;
}
}
if ((p = strtok(NULL, delim)) != NULL) {
if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
if (isnumber(p))
Quality = atoi(p);
else {
@ -574,14 +575,14 @@ void cSVDRP::CmdGRAB(const char *Option)
return;
}
}
if ((p = strtok(NULL, delim)) != NULL) {
if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
if (isnumber(p))
SizeX = atoi(p);
else {
Reply(501, "Illegal sizex \"%s\"", p);
return;
}
if ((p = strtok(NULL, delim)) != NULL) {
if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
if (isnumber(p))
SizeY = atoi(p);
else {
@ -594,7 +595,7 @@ void cSVDRP::CmdGRAB(const char *Option)
return;
}
}
if ((p = strtok(NULL, delim)) != NULL) {
if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
Reply(501, "Unexpected parameter \"%s\"", p);
return;
}
@ -727,7 +728,8 @@ void cSVDRP::CmdLSTE(const char *Option)
char buf[strlen(Option) + 1];
strcpy(buf, Option);
const char *delim = " \t";
char *p = strtok(buf, delim);
char *strtok_next;
char *p = strtok_r(buf, delim, &strtok_next);
while (p && DumpMode == dmAll) {
if (strcasecmp(p, "NOW") == 0)
DumpMode = dmPresent;
@ -735,7 +737,7 @@ void cSVDRP::CmdLSTE(const char *Option)
DumpMode = dmFollowing;
else if (strcasecmp(p, "AT") == 0) {
DumpMode = dmAtTime;
if ((p = strtok(NULL, delim)) != NULL) {
if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
if (isnumber(p))
AtTime = strtol(p, NULL, 10);
else {
@ -770,7 +772,7 @@ void cSVDRP::CmdLSTE(const char *Option)
Reply(501, "Unknown option: \"%s\"", p);
return;
}
p = strtok(NULL, delim);
p = strtok_r(NULL, delim, &strtok_next);
}
}
FILE *f = fdopen(file, "w");
@ -995,11 +997,8 @@ void cSVDRP::CmdNEXT(const char *Option)
if (t) {
time_t Start = t->StartTime();
int Number = t->Index() + 1;
if (!*Option) {
char *s = ctime(&Start);
s[strlen(s) - 1] = 0; // strip trailing newline
Reply(250, "%d %s", Number, s);
}
if (!*Option)
Reply(250, "%d %s", Number, *cCtime(Start));
else if (strcasecmp(Option, "ABS") == 0)
Reply(250, "%d %ld", Number, Start);
else if (strcasecmp(Option, "REL") == 0)
@ -1152,7 +1151,7 @@ bool cSVDRP::Process(void)
char buffer[BUFSIZ];
gethostname(buffer, sizeof(buffer));
time_t now = time(NULL);
Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, ctime(&now));
Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, *cCtime(now));
}
if (NewConnection)
lastActivity = time(NULL);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: themes.c 1.3 2004/06/18 15:05:07 kls Exp $
* $Id: themes.c 1.4 2004/12/19 15:49:49 kls Exp $
*/
#include "themes.h"
@ -96,7 +96,8 @@ bool cTheme::Load(const char *FileName, bool OnlyDescriptions)
result = true;
char *s;
const char *error = NULL;
while ((s = readline(f)) != NULL) {
cReadLine ReadLine;
while ((s = ReadLine.Read(f)) != NULL) {
line++;
char *p = strchr(s, '#');
if (p)
@ -242,29 +243,26 @@ bool cThemes::Load(const char *SkinName)
{
Clear();
if (themesDirectory) {
DIR *d = opendir(themesDirectory);
if (d) {
struct dirent *e;
while ((e = readdir(d)) != NULL) {
if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) {
if (strstr(e->d_name, SkinName) == e->d_name && e->d_name[strlen(SkinName)] == '-') {
const char *FileName = AddDirectory(themesDirectory, e->d_name);
cTheme Theme;
if (Theme.Load(FileName, true)) {
names = (char **)realloc(names, (numThemes + 1) * sizeof(char *));
names[numThemes] = strdup(Theme.Name());
fileNames = (char **)realloc(fileNames, (numThemes + 1) * sizeof(char *));
fileNames[numThemes] = strdup(FileName);
descriptions = (char **)realloc(descriptions, (numThemes + 1) * sizeof(char *));
descriptions[numThemes] = strdup(Theme.Description());
numThemes++;
}
cReadDir d(themesDirectory);
struct dirent *e;
while ((e = d.Next()) != NULL) {
if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) {
if (strstr(e->d_name, SkinName) == e->d_name && e->d_name[strlen(SkinName)] == '-') {
cAddDirectory FileName(themesDirectory, e->d_name);
cTheme Theme;
if (Theme.Load(*FileName, true)) {
names = (char **)realloc(names, (numThemes + 1) * sizeof(char *));
names[numThemes] = strdup(Theme.Name());
fileNames = (char **)realloc(fileNames, (numThemes + 1) * sizeof(char *));
fileNames[numThemes] = strdup(*FileName);
descriptions = (char **)realloc(descriptions, (numThemes + 1) * sizeof(char *));
descriptions[numThemes] = strdup(Theme.Description());
numThemes++;
}
}
}
closedir(d);
return numThemes > 0;
}
}
return numThemes > 0;
}
return false;
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: timers.c 1.19 2004/11/22 16:49:15 kls Exp $
* $Id: timers.c 1.20 2004/12/19 14:11:29 kls Exp $
*/
#include "timers.h"
@ -111,7 +111,7 @@ const char *cTimer::ToText(bool UseChannelID)
free(buffer);
strreplace(file, ':', '|');
strreplace(summary, '\n', '|');
asprintf(&buffer, "%d:%s:%s:%04d:%04d:%d:%d:%s:%s\n", flags, UseChannelID ? Channel()->GetChannelID().ToString() : itoa(Channel()->Number()), PrintDay(day, firstday), start, stop, priority, lifetime, file, summary ? summary : "");
asprintf(&buffer, "%d:%s:%s:%04d:%04d:%d:%d:%s:%s\n", flags, UseChannelID ? Channel()->GetChannelID().ToString() : *cItoa(Channel()->Number()), PrintDay(day, firstday), start, stop, priority, lifetime, file, summary ? summary : "");
strreplace(summary, '|', '\n');
strreplace(file, '|', ':');
return buffer;

200
tools.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.c 1.82 2004/11/21 14:36:34 kls Exp $
* $Id: tools.c 1.83 2004/12/19 16:08:50 kls Exp $
*/
#include "tools.h"
@ -65,18 +65,6 @@ void writechar(int filedes, char c)
safe_write(filedes, &c, sizeof(c));
}
char *readline(FILE *f)
{
static char buffer[MAXPARSEBUFFER];
if (fgets(buffer, sizeof(buffer), f) > 0) {
int l = strlen(buffer) - 1;
if (l >= 0 && buffer[l] == '\n')
buffer[l] = 0;
return buffer;
}
return NULL;
}
char *strcpyrealloc(char *dest, const char *src)
{
if (src) {
@ -167,29 +155,6 @@ char *compactspace(char *s)
return s;
}
const char *strescape(const char *s, const char *chars)
{
static char *buffer = NULL;
const char *p = s;
char *t = NULL;
while (*p) {
if (strchr(chars, *p)) {
if (!t) {
buffer = (char *)realloc(buffer, 2 * strlen(s) + 1);
t = buffer + (p - s);
s = strcpy(buffer, s);
}
*t++ = '\\';
}
if (t)
*t++ = *p;
p++;
}
if (t)
*t = 0;
return s;
}
bool startswith(const char *s, const char *p)
{
while (*p) {
@ -253,21 +218,6 @@ bool isnumber(const char *s)
return true;
}
const char *itoa(int n)
{
static char buf[16];
snprintf(buf, sizeof(buf), "%d", n);
return buf;
}
const char *AddDirectory(const char *DirName, const char *FileName)
{
static char *buf = NULL;
free(buf);
asprintf(&buf, "%s/%s", DirName && *DirName ? DirName : ".", FileName);
return buf;
}
int FreeDiskSpaceMB(const char *Directory, int *UsedMB)
{
if (UsedMB)
@ -336,10 +286,10 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
struct stat st;
if (stat(FileName, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
DIR *d = opendir(FileName);
if (d) {
cReadDir d(FileName);
if (d.Ok()) {
struct dirent *e;
while ((e = readdir(d)) != NULL) {
while ((e = d.Next()) != NULL) {
if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) {
char *buffer;
asprintf(&buffer, "%s/%s", FileName, e->d_name);
@ -367,7 +317,6 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
free(buffer);
}
}
closedir(d);
}
else {
LOG_ERROR_STR(FileName);
@ -389,11 +338,11 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis)
{
DIR *d = opendir(DirName);
if (d) {
cReadDir d(DirName);
if (d.Ok()) {
bool empty = true;
struct dirent *e;
while ((e = readdir(d)) != NULL) {
while ((e = d.Next()) != NULL) {
if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..") && strcmp(e->d_name, "lost+found")) {
char *buffer;
asprintf(&buffer, "%s/%s", DirName, e->d_name);
@ -414,7 +363,6 @@ bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis)
free(buffer);
}
}
closedir(d);
if (RemoveThis && empty) {
dsyslog("removing %s", DirName);
if (remove(DirName) < 0) {
@ -451,7 +399,7 @@ char *ReadLink(const char *FileName)
bool SpinUpDisk(const char *FileName)
{
static char *buf = NULL;
char *buf = NULL;
for (int n = 0; n < 10; n++) {
free(buf);
if (DirectoryOk(FileName))
@ -471,12 +419,14 @@ bool SpinUpDisk(const char *FileName)
double seconds = (((long long)tp2.tv_sec * 1000000 + tp2.tv_usec) - ((long long)tp1.tv_sec * 1000000 + tp1.tv_usec)) / 1000000.0;
if (seconds > 0.5)
dsyslog("SpinUpDisk took %.2f seconds\n", seconds);
free(buf);
return true;
}
else
LOG_ERROR_STR(buf);
}
}
free(buf);
esyslog("ERROR: SpinUpDisk failed");
return false;
}
@ -489,35 +439,119 @@ time_t LastModifiedTime(const char *FileName)
return 0;
}
const char *WeekDayName(int WeekDay)
// --- cBufferedStringFunction -----------------------------------------------
cBufferedStringFunction::cBufferedStringFunction(void)
{
buffer = NULL;
result = ""; // makes sure dereferencing it doesn't hurt
}
cBufferedStringFunction::~cBufferedStringFunction()
{
free(buffer);
}
// --- cAddDirectory ---------------------------------------------------------
cAddDirectory::cAddDirectory(const char *DirName, const char *FileName)
{
asprintf(&buffer, "%s/%s", DirName && *DirName ? DirName : ".", FileName);
result = buffer;
}
// --- cStrEscape ------------------------------------------------------------
cStrEscape::cStrEscape(const char *s, const char *chars)
{
buffer = NULL;
const char *p = s;
char *t = NULL;
while (*p) {
if (strchr(chars, *p)) {
if (!t) {
buffer = (char *)realloc(buffer, 2 * strlen(s) + 1);
t = buffer + (p - s);
s = strcpy(buffer, s);
}
*t++ = '\\';
}
if (t)
*t++ = *p;
p++;
}
if (t)
*t = 0;
result = s;
}
// --- cCtime ----------------------------------------------------------------
cCtime::cCtime(time_t Time)
{
if (ctime_r(&Time, buffer)) {
buffer[strlen(buffer) - 1] = 0; // strip trailing newline
result = buffer;
}
}
// --- cItoa -----------------------------------------------------------------
cItoa::cItoa(int n)
{
snprintf(buffer, sizeof(buffer), "%d", n);
result = buffer;
}
// --- cWeekDayName ----------------------------------------------------------
cWeekDayName::cWeekDayName(int WeekDay)
{
WeekDayName(WeekDay);
}
cWeekDayName::cWeekDayName(time_t t)
{
struct tm tm_r;
WeekDayName(localtime_r(&t, &tm_r)->tm_wday);
}
void cWeekDayName::WeekDayName(int WeekDay)
{
static char buffer[4];
WeekDay = WeekDay == 0 ? 6 : WeekDay - 1; // we start with monday==0!
if (0 <= WeekDay && WeekDay <= 6) {
const char *day = tr("MonTueWedThuFriSatSun");
day += WeekDay * 3;
strncpy(buffer, day, 3);
return buffer;
strn0cpy(buffer, day, sizeof(buffer));
result = buffer;
}
else
return "???";
result = "???";
}
const char *WeekDayName(time_t t)
{
struct tm tm_r;
return WeekDayName(localtime_r(&t, &tm_r)->tm_wday);
}
// --- cDayDateTime ----------------------------------------------------------
const char *DayDateTime(time_t t)
cDayDateTime::cDayDateTime(time_t t)
{
static char buffer[32];
if (t == 0)
time(&t);
struct tm tm_r;
tm *tm = localtime_r(&t, &tm_r);
snprintf(buffer, sizeof(buffer), "%s %2d.%02d %02d:%02d", WeekDayName(tm->tm_wday), tm->tm_mday, tm->tm_mon + 1, tm->tm_hour, tm->tm_min);
return buffer;
snprintf(buffer, sizeof(buffer), "%s %2d.%02d %02d:%02d", *cWeekDayName(tm->tm_wday), tm->tm_mday, tm->tm_mon + 1, tm->tm_hour, tm->tm_min);
result = buffer;
}
// --- cReadLine -------------------------------------------------------------
char *cReadLine::Read(FILE *f)
{
if (fgets(buffer, sizeof(buffer), f) > 0) {
int l = strlen(buffer) - 1;
if (l >= 0 && buffer[l] == '\n')
buffer[l] = 0;
return buffer;
}
return NULL;
}
// --- cPoller ---------------------------------------------------------------
@ -557,6 +591,24 @@ bool cPoller::Poll(int TimeoutMs)
return false;
}
// --- cReadDir --------------------------------------------------------------
cReadDir::cReadDir(const char *Directory)
{
directory = opendir(Directory);
}
cReadDir::~cReadDir()
{
if (directory)
closedir(directory);
}
struct dirent *cReadDir::Next(void)
{
return directory && readdir_r(directory, &u.d, &result) == 0 ? result : NULL;
}
// --- cFile -----------------------------------------------------------------
bool cFile::files[FD_SETSIZE] = { false };

85
tools.h
View File

@ -4,14 +4,16 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.h 1.58 2004/10/31 16:16:37 kls Exp $
* $Id: tools.h 1.59 2004/12/19 14:49:48 kls Exp $
*/
#ifndef __TOOLS_H
#define __TOOLS_H
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <objalloc.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
@ -58,7 +60,6 @@ int BCD2INT(int x);
ssize_t safe_read(int filedes, void *buffer, size_t size);
ssize_t safe_write(int filedes, const void *buffer, size_t size);
void writechar(int filedes, char c);
char *readline(FILE *f);
char *strcpyrealloc(char *dest, const char *src);
char *strn0cpy(char *dest, const char *src, size_t n);
char *strreplace(char *s, char c1, char c2);
@ -66,7 +67,6 @@ char *strreplace(char *s, const char *s1, const char *s2); ///< re-allocates 's'
char *skipspace(const char *s);
char *stripspace(char *s);
char *compactspace(char *s);
const char *strescape(const char *s, const char *chars); ///< \warning returns a statically allocated string!
bool startswith(const char *s, const char *p);
bool endswith(const char *s, const char *p);
bool isempty(const char *s);
@ -74,8 +74,6 @@ int numdigits(int n);
int time_ms(void);
void delay_ms(int ms);
bool isnumber(const char *s);
const char *itoa(int n); ///< \warning returns a statically allocated string!
const char *AddDirectory(const char *DirName, const char *FileName); ///< \warning returns a statically allocated string!
int FreeDiskSpaceMB(const char *Directory, int *UsedMB = NULL);
bool DirectoryOk(const char *DirName, bool LogErrors = false);
bool MakeDirs(const char *FileName, bool IsDirectory = false);
@ -84,9 +82,65 @@ bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false);
char *ReadLink(const char *FileName);
bool SpinUpDisk(const char *FileName);
time_t LastModifiedTime(const char *FileName);
const char *WeekDayName(int WeekDay); ///< \warning returns a statically allocated string!
const char *WeekDayName(time_t t); ///< \warning returns a statically allocated string!
const char *DayDateTime(time_t t = 0); ///< \warning returns a statically allocated string!
class cBufferedStringFunction {
protected:
char *buffer;
const char *result;
public:
cBufferedStringFunction(void);
virtual ~cBufferedStringFunction();
const char * operator * () { return result; }
};
template<int size> class cBufferedStringFunctionFix : public cBufferedStringFunction {
protected:
char buffer[size];
const char *result;
public:
cBufferedStringFunctionFix(void) { result = ""; } // makes sure dereferencing it doesn't hurt
const char * operator * () { return result; }
};
class cAddDirectory : public cBufferedStringFunction {
public:
cAddDirectory(const char *DirName, const char *FileName);
};
class cStrEscape : public cBufferedStringFunction {
public:
cStrEscape(const char *s, const char *chars);
};
class cCtime : public cBufferedStringFunctionFix<32> {
public:
cCtime(time_t Time);
};
class cItoa : public cBufferedStringFunctionFix<16> {
public:
cItoa(int n);
};
class cWeekDayName : public cBufferedStringFunctionFix<4> {
private:
void WeekDayName(int WeekDay);
public:
cWeekDayName(int WeekDay);
cWeekDayName(time_t t);
};
class cDayDateTime : public cBufferedStringFunctionFix<32> {
public:
cDayDateTime(time_t t = 0);
};
class cReadLine {
private:
char buffer[MAXPARSEBUFFER];
public:
char *Read(FILE *f);
};
class cPoller {
private:
@ -99,6 +153,21 @@ public:
bool Poll(int TimeoutMs = 0);
};
class cReadDir {
private:
DIR *directory;
struct dirent *result;
union { // according to "The GNU C Library Reference Manual"
struct dirent d;
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
} u;
public:
cReadDir(const char *Directory);
~cReadDir();
bool Ok(void) { return directory != NULL; }
struct dirent *Next(void);
};
class cFile {
private:
static bool files[];

43
vdr.c
View File

@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/vdr
*
* $Id: vdr.c 1.194 2004/12/05 13:20:29 kls Exp $
* $Id: vdr.c 1.195 2004/12/19 15:28:34 kls Exp $
*/
#include <getopt.h>
@ -384,19 +384,19 @@ int main(int argc, char *argv[])
ConfigDirectory = VideoDirectory;
cPlugin::SetConfigDirectory(ConfigDirectory);
cThemes::SetThemesDirectory(AddDirectory(ConfigDirectory, "themes"));
cThemes::SetThemesDirectory(*cAddDirectory(ConfigDirectory, "themes"));
Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
if (!(Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true, true) &&
Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC) &&
Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true) &&
Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")) &&
Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true) &&
RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true) &&
SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true) &&
CaDefinitions.Load(AddDirectory(ConfigDirectory, "ca.conf"), true) &&
Keys.Load(AddDirectory(ConfigDirectory, "remote.conf")) &&
KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true)
Setup.Load(*cAddDirectory(ConfigDirectory, "setup.conf"));
if (!(Sources.Load(*cAddDirectory(ConfigDirectory, "sources.conf"), true, true) &&
Diseqcs.Load(*cAddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC) &&
Channels.Load(*cAddDirectory(ConfigDirectory, "channels.conf"), false, true) &&
Timers.Load(*cAddDirectory(ConfigDirectory, "timers.conf")) &&
Commands.Load(*cAddDirectory(ConfigDirectory, "commands.conf"), true) &&
RecordingCommands.Load(*cAddDirectory(ConfigDirectory, "reccmds.conf"), true) &&
SVDRPhosts.Load(*cAddDirectory(ConfigDirectory, "svdrphosts.conf"), true) &&
CaDefinitions.Load(*cAddDirectory(ConfigDirectory, "ca.conf"), true) &&
Keys.Load(*cAddDirectory(ConfigDirectory, "remote.conf")) &&
KeyMacros.Load(*cAddDirectory(ConfigDirectory, "keymacros.conf"), true)
))
EXIT(2);
@ -405,13 +405,16 @@ int main(int argc, char *argv[])
// EPG data:
if (EpgDataFileName) {
if (DirectoryOk(EpgDataFileName))
EpgDataFileName = AddDirectory(EpgDataFileName, DEFAULTEPGDATAFILENAME);
const char *EpgDirectory = NULL;
if (DirectoryOk(EpgDataFileName)) {
EpgDirectory = EpgDataFileName;
EpgDataFileName = DEFAULTEPGDATAFILENAME;
}
else if (*EpgDataFileName != '/' && *EpgDataFileName != '.')
EpgDataFileName = AddDirectory(VideoDirectory, EpgDataFileName);
EpgDirectory = VideoDirectory;
cSchedules::SetEpgDataFileName(*cAddDirectory(EpgDirectory, EpgDataFileName));
cSchedules::Read();
}
cSchedules::SetEpgDataFileName(EpgDataFileName);
cSchedules::Read();
// DVB interfaces:
@ -867,7 +870,7 @@ int main(int argc, char *argv[])
if (!Next || Delta > Setup.MinEventTimeout * 60 || ForceShutdown) {
ForceShutdown = false;
if (timer)
dsyslog("next timer event at %s", ctime(&Next));
dsyslog("next timer event at %s", *cCtime(Next));
if (WatchdogTimeout > 0)
signal(SIGALRM, SIG_IGN);
if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) {
@ -875,7 +878,7 @@ int main(int argc, char *argv[])
const char *File = timer ? timer->File() : "";
Delta = Next - time(NULL); // compensates for Confirm() timeout
char *cmd;
asprintf(&cmd, "%s %ld %ld %d \"%s\" %d", Shutdown, Next, Delta, Channel, strescape(File, "\"$"), UserShutdown);
asprintf(&cmd, "%s %ld %ld %d \"%s\" %d", Shutdown, Next, Delta, Channel, *cStrEscape(File, "\"$"), UserShutdown);
isyslog("executing '%s'", cmd);
SystemExec(cmd);
free(cmd);