vdr  2.2.0
themes.c
Go to the documentation of this file.
1 /*
2  * themes.c: Color themes used by skins
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: themes.c 3.0 2012/02/17 13:57:32 kls Exp $
8  */
9 
10 #include "themes.h"
11 #include <dirent.h>
12 #include <string.h>
13 #include "config.h"
14 #include "tools.h"
15 
16 // --- cTheme ----------------------------------------------------------------
17 
19 {
20  name = strdup("default");
21  memset(colorNames, 0, sizeof(colorNames));
22  memset(colorValues, 0, sizeof(colorValues));
23  descriptions[0] = strdup("Default");
24 }
25 
27 {
28  free(name);
29  for (int i = 0; i < MaxThemeColors; i++)
30  free(colorNames[i]);
31 }
32 
33 bool cTheme::FileNameOk(const char *FileName, bool SetName)
34 {
35  const char *error = NULL;
36  if (!isempty(FileName)) {
37  const char *d = strrchr(FileName, '/');
38  if (d)
39  FileName = d + 1;
40  const char *n = strchr(FileName, '-');
41  if (n) {
42  if (n > FileName) {
43  if (!strchr(++n, '-')) {
44  const char *e = strchr(n, '.');
45  if (e && strcmp(e, ".theme") == 0) {
46  if (e - n >= 1) {
47  // FileName is ok
48  if (SetName) {
49  free(name);
50  name = strndup(n, e - n);
51  }
52  }
53  else
54  error = "missing theme name";
55  }
56  else
57  error = "invalid extension";
58  }
59  else
60  error = "too many '-'";
61  }
62  else
63  error = "missing skin name";
64  }
65  else
66  error = "missing '-'";
67  }
68  else
69  error = "empty";
70  if (error)
71  esyslog("ERROR: invalid theme file name (%s): '%s'", error, FileName);
72  return !error;
73 }
74 
75 const char *cTheme::Description(void)
76 {
77  char *s = descriptions[I18nCurrentLanguage()];
78  if (!s)
79  s = descriptions[0];
80  return s ? s : name;
81 }
82 
83 bool cTheme::Load(const char *FileName, bool OnlyDescriptions)
84 {
85  if (!FileNameOk(FileName, true))
86  return false;
87  bool result = false;
88  if (!OnlyDescriptions)
89  isyslog("loading %s", FileName);
90  FILE *f = fopen(FileName, "r");
91  if (f) {
92  int line = 0;
93  result = true;
94  char *s;
95  const char *error = NULL;
96  cReadLine ReadLine;
97  while ((s = ReadLine.Read(f)) != NULL) {
98  line++;
99  char *p = strchr(s, '#');
100  if (p)
101  *p = 0;
102  s = stripspace(skipspace(s));
103  if (!isempty(s)) {
104  char *n = s;
105  char *v = strchr(s, '=');
106  if (v) {
107  *v++ = 0;
108  n = stripspace(skipspace(n));
109  v = stripspace(skipspace(v));
110  if (strstr(n, "Description") == n) {
111  int lang = 0;
112  char *l = strchr(n, '.');
113  if (l)
114  lang = I18nLanguageIndex(++l);
115  if (lang >= 0) {
116  free(descriptions[lang]);
117  descriptions[lang] = strdup(v);
118  }
119  else
120  error = "invalid language code";
121  }
122  else if (!OnlyDescriptions) {
123  for (int i = 0; i < MaxThemeColors; i++) {
124  if (colorNames[i]) {
125  if (strcmp(n, colorNames[i]) == 0) {
126  char *p = NULL;
127  errno = 0;
128  tColor c = strtoul(v, &p, 16);
129  if (!errno && !*p)
130  colorValues[i] = c;
131  else
132  error = "invalid color value";
133  break;
134  }
135  }
136  else {
137  error = "unknown color name";
138  break;
139  }
140  }
141  }
142  }
143  else
144  error = "missing value";
145  }
146  if (error) {
147  result = false;
148  break;
149  }
150  }
151  if (!result)
152  esyslog("ERROR: error in %s, line %d%s%s", FileName, line, error ? ": " : "", error ? error : "");
153  fclose(f);
154  }
155  else
156  LOG_ERROR_STR(FileName);
157  return result;
158 }
159 
160 bool cTheme::Save(const char *FileName)
161 {
162  if (!FileNameOk(FileName))
163  return false;
164  bool result = true;
165  cSafeFile f(FileName);
166  if (f.Open()) {
167  for (int i = 0; i < I18nLanguages()->Size(); i++) {
168  if (descriptions[i])
169  fprintf(f, "Description%s%.*s = %s\n", i ? "." : "", 3, i ? I18nLanguageCode(i) : "", descriptions[i]);
170  }
171  for (int i = 0; i < MaxThemeColors; i++) {
172  if (colorNames[i])
173  fprintf(f, "%s = %08X\n", colorNames[i], colorValues[i]);
174  }
175  if (!f.Close())
176  result = false;
177  }
178  else
179  result = false;
180  return result;
181 }
182 
184 {
185  for (int i = 0; i < MaxThemeColors; i++) {
186  if (colorNames[i]) {
187  if (strcmp(Name, colorNames[i]) == 0) {
188  colorValues[i] = Color;
189  return i;
190  }
191  }
192  else {
193  colorNames[i] = strdup(Name);
194  colorValues[i] = Color;
195  return i;
196  }
197  }
198  return -1;
199 }
200 
201 tColor cTheme::Color(int Subject)
202 {
203  return (Subject >= 0 && Subject < MaxThemeColors) ? colorValues[Subject] : 0;
204 }
205 
206 // --- cThemes ---------------------------------------------------------------
207 
208 char *cThemes::themesDirectory = NULL;
209 
211 {
212  numThemes = 0;
213  names = 0;
214  fileNames = NULL;
215  descriptions = NULL;
216 }
217 
219 {
220  Clear();
221 }
222 
223 void cThemes::Clear(void)
224 {
225  for (int i = 0; i < numThemes; i++) {
226  free(names[i]);
227  free(fileNames[i]);
228  free(descriptions[i]);
229  }
230  free(names);
231  free(fileNames);
232  free(descriptions);
233  numThemes = 0;
234  names = 0;
235  fileNames = NULL;
236  descriptions = NULL;
237 }
238 
239 bool cThemes::Load(const char *SkinName)
240 {
241  Clear();
242  if (themesDirectory) {
243  cReadDir d(themesDirectory);
244  struct dirent *e;
245  while ((e = d.Next()) != NULL) {
246  if (strstr(e->d_name, SkinName) == e->d_name && e->d_name[strlen(SkinName)] == '-') {
247  cString FileName = AddDirectory(themesDirectory, e->d_name);
248  cTheme Theme;
249  if (Theme.Load(*FileName, true)) {
250  if (char **NewBuffer = (char **)realloc(names, (numThemes + 1) * sizeof(char *))) {
251  names = NewBuffer;
252  names[numThemes] = strdup(Theme.Name());
253  }
254  else {
255  esyslog("ERROR: out of memory");
256  break;
257  }
258  if (char **NewBuffer = (char **)realloc(fileNames, (numThemes + 1) * sizeof(char *))) {
259  fileNames = NewBuffer;
260  fileNames[numThemes] = strdup(*FileName);
261  }
262  else {
263  esyslog("ERROR: out of memory");
264  break;
265  }
266  if (char **NewBuffer = (char **)realloc(descriptions, (numThemes + 1) * sizeof(char *))) {
267  descriptions = NewBuffer;
268  descriptions[numThemes] = strdup(Theme.Description());
269  }
270  else {
271  esyslog("ERROR: out of memory");
272  break;
273  }
274  numThemes++;
275  }
276  }
277  }
278  return numThemes > 0;
279  }
280  return false;
281 }
282 
284 {
285  int index = 0;
286  for (int i = 0; i < numThemes; i++) {
287  if (strcmp(descriptions[i], Description) == 0)
288  return i;
289  if (strcmp(descriptions[i], "Default") == 0)
290  index = i;
291  }
292  return index;
293 }
294 
295 void cThemes::SetThemesDirectory(const char *ThemesDirectory)
296 {
297  free(themesDirectory);
298  themesDirectory = strdup(ThemesDirectory);
299  MakeDirs(themesDirectory, true);
300 }
301 
302 void cThemes::Load(const char *SkinName, const char *ThemeName, cTheme *Theme)
303 {
304  cString FileName = cString::sprintf("%s/%s-%s.theme", themesDirectory, SkinName, ThemeName);
305  if (access(FileName, F_OK) == 0) // the file exists
306  Theme->Load(FileName);
307 }
308 
309 void cThemes::Save(const char *SkinName, cTheme *Theme)
310 {
311  cString FileName = cString::sprintf("%s/%s-%s.theme", themesDirectory, SkinName, Theme->Name());
312  if (access(FileName, F_OK) != 0) // the file does not exist
313  Theme->Save(FileName);
314 }
struct dirent * Next(void)
Definition: tools.c:1466
~cTheme()
Definition: themes.c:26
static void SetThemesDirectory(const char *ThemesDirectory)
Definition: themes.c:295
bool isempty(const char *s)
Definition: tools.c:297
cString AddDirectory(const char *DirName, const char *FileName)
Definition: tools.c:350
bool Close(void)
Definition: tools.c:1672
int I18nCurrentLanguage(void)
Returns the index of the current language.
Definition: i18n.c:183
cTheme(void)
Creates a new theme class.
Definition: themes.c:18
bool Load(const char *SkinName)
Definition: themes.c:239
~cThemes()
Definition: themes.c:218
char * stripspace(char *s)
Definition: tools.c:201
bool Open(void)
Definition: tools.c:1662
bool MakeDirs(const char *FileName, bool IsDirectory)
Definition: tools.c:445
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1080
#define esyslog(a...)
Definition: tools.h:34
#define LOG_ERROR_STR(s)
Definition: tools.h:39
int GetThemeIndex(const char *Description)
Definition: themes.c:283
char * Read(FILE *f)
Definition: tools.c:1398
static void Save(const char *SkinName, cTheme *Theme)
Definition: themes.c:309
Definition: themes.h:17
bool Save(const char *FileName)
Saves the theme data to the given file.
Definition: themes.c:160
bool FileNameOk(const char *FileName, bool SetName=false)
Definition: themes.c:33
const char * Description(void)
Returns a user visible, single line description of this theme.
Definition: themes.c:75
bool Load(const char *FileName, bool OnlyDescriptions=false)
Loads the theme data from the given file.
Definition: themes.c:83
static char * themesDirectory
Definition: themes.h:67
static cTheme Theme
Definition: skinclassic.c:21
int Size(void) const
Definition: tools.h:551
const char * I18nLanguageCode(int Language)
Returns the three letter language code of the given Language (which is an index as returned by I18nCu...
Definition: i18n.c:223
void Clear(void)
Definition: themes.c:223
const char * Name(void)
Definition: themes.h:30
cThemes(void)
Definition: themes.c:210
int AddColor(const char *Name, tColor Color)
Adds a color with the given Name to this theme, initializes it with Color and returns an index into t...
Definition: themes.c:183
const cStringList * I18nLanguages(void)
Returns the list of available languages.
Definition: i18n.c:201
char * skipspace(const char *s)
Definition: tools.h:200
tColor colorValues[MaxThemeColors]
Definition: themes.h:24
#define isyslog(a...)
Definition: tools.h:35
char * name
Definition: themes.h:21
char * colorNames[MaxThemeColors]
Definition: themes.h:23
int I18nLanguageIndex(const char *Code)
Returns the index of the language with the given three letter language Code.
Definition: i18n.c:228
tColor Color(int Subject)
Returns the color for the given Subject.
Definition: themes.c:201
Definition: tools.h:168
uint32_t tColor
Definition: font.h:29
cStringList descriptions
Definition: themes.h:22