From 1d3495a0f09b1949efbba553a3d2a152ad2be617 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 19 Dec 2004 16:33:34 +0100 Subject: [PATCH] Made several functions threadsafe --- CONTRIBUTORS | 2 + HISTORY | 12 ++ PLUGINS/src/skincurses/HISTORY | 4 + PLUGINS/src/sky/HISTORY | 4 + PLUGINS/src/sky/sky.c | 6 +- channels.c | 11 +- keys.c | 5 +- osd.c | 5 +- plugin.c | 31 +++-- recording.c | 70 ++++++------ skinclassic.c | 10 +- skinsttng.c | 14 +-- svdrp.c | 31 +++-- themes.c | 42 ++++--- timers.c | 4 +- tools.c | 200 +++++++++++++++++++++------------ tools.h | 85 ++++++++++++-- vdr.c | 43 +++---- 18 files changed, 360 insertions(+), 219 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index d4c6385d..b62f8a32 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -348,6 +348,8 @@ Rainer Zocholl 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 for adding EPG scanning for another 4 days diff --git a/HISTORY b/HISTORY index 8d8dca2c..0f16486e 100644 --- a/HISTORY +++ b/HISTORY @@ -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 diff --git a/PLUGINS/src/skincurses/HISTORY b/PLUGINS/src/skincurses/HISTORY index df673583..057fb6f8 100644 --- a/PLUGINS/src/skincurses/HISTORY +++ b/PLUGINS/src/skincurses/HISTORY @@ -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. diff --git a/PLUGINS/src/sky/HISTORY b/PLUGINS/src/sky/HISTORY index 490ee62b..f1f22a69 100644 --- a/PLUGINS/src/sky/HISTORY +++ b/PLUGINS/src/sky/HISTORY @@ -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. diff --git a/PLUGINS/src/sky/sky.c b/PLUGINS/src/sky/sky.c index 8936774e..49afea1d 100644 --- a/PLUGINS/src/sky/sky.c +++ b/PLUGINS/src/sky/sky.c @@ -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 @@ -14,7 +14,7 @@ #include #include -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; } diff --git a/channels.c b/channels.c index 5d500ece..67949e24 100644 --- a/channels.c +++ b/channels.c @@ -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) diff --git a/keys.c b/keys.c index 5529f323..aaeee97e 100644 --- a/keys.c +++ b/keys.c @@ -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) { diff --git a/osd.c b/osd.c index 6944e675..8b10f74f 100644 --- a/osd.c +++ b/osd.c @@ -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) { diff --git a/plugin.c b/plugin.c index 7f211b3c..a06d003c 100644 --- a/plugin.c +++ b/plugin.c @@ -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)); diff --git a/recording.c b/recording.c index 5a703db2..aa9f6dcf 100644 --- a/recording.c +++ b/recording.c @@ -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::Load(MarksFile)) { + if (cConfig::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); diff --git a/skinclassic.c b/skinclassic.c index 9dd90942..3b9609f3 100644 --- a/skinclassic.c +++ b/skinclassic.c @@ -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(); } diff --git a/skinsttng.c b/skinsttng.c index f1f79bf5..cf60ae14 100644 --- a/skinsttng.c +++ b/skinsttng.c @@ -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(); } diff --git a/svdrp.c b/svdrp.c index eec6869c..365e4a36 100644 --- a/svdrp.c +++ b/svdrp.c @@ -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); diff --git a/themes.c b/themes.c index 0a9b951d..b4bffea3 100644 --- a/themes.c +++ b/themes.c @@ -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; } diff --git a/timers.c b/timers.c index 921a2256..5c6ba70e 100644 --- a/timers.c +++ b/timers.c @@ -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; diff --git a/tools.c b/tools.c index 41d0c725..111b18c2 100644 --- a/tools.c +++ b/tools.c @@ -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 }; diff --git a/tools.h b/tools.h index 9e0abff4..bbbd5704 100644 --- a/tools.h +++ b/tools.h @@ -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 #include #include +#include #include #include #include @@ -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 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[]; diff --git a/vdr.c b/vdr.c index 664cc7d3..2276e7e8 100644 --- a/vdr.c +++ b/vdr.c @@ -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 @@ -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);