]> git.vomp.tv Git - vompserver.git/blob - config.c
Fix for APIVERSNUM / NAME on old VDRs
[vompserver.git] / config.c
1 /*
2     Copyright 2004-2005 Chris Tallon
3     Copyright 2004-2005 University Of Bradford
4
5     This file is part of VOMP.
6
7     VOMP is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     VOMP is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with VOMP; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21
22 #include "config.h"
23
24 Config::Config()
25 {
26   initted = 0;
27   lastLineLength = 0;
28   log = Log::getInstance();
29 }
30
31 int Config::init(char* takeFileName)
32 {
33   if (initted) return 1;
34
35   pthread_mutex_init(&fileLock, NULL);
36
37   if (strlen(takeFileName) > (MAX_FILENAME_LENGTH - 1))
38   {
39     log->log("Config", Log::DEBUG, "Config error: Config filename too long");
40     return 0;
41   }
42
43   strcpy(fileName, takeFileName);
44   strcpy(fileNameTemp, takeFileName);
45   strcat(fileNameTemp, ".tmp");
46
47   file = fopen(fileName, "r");
48   if (!file)
49   {
50     file = fopen(fileName, "w");
51     if (!file)
52     {
53       log->log("Config", Log::DEBUG, "Config error: Could not access config file");
54       return 0;
55     }
56   }
57   fclose(file);
58
59   initted = 1;
60   log->log("Config", Log::DEBUG, "Opened config file: %s", fileName);
61
62   return 1;
63 }
64
65 int Config::status()
66 {
67   return initted;
68 }
69
70 int Config::shutdown()
71 {
72   if (!initted) return 1;
73
74   pthread_mutex_lock(&fileLock);
75   initted = 0;
76   pthread_mutex_unlock(&fileLock);
77   pthread_mutex_destroy(&fileLock);
78
79   return 1;
80 }
81
82 int Config::openFile()
83 {
84   if (!initted) return 0;
85   if (pthread_mutex_lock(&fileLock))
86   {
87     log->log("Config", Log::DEBUG, "Config error: Could not get lock");
88     return 0;
89   }
90   if (!initted)
91   {
92     log->log("Config", Log::DEBUG, "Config error: Initted 0 after lock");
93     pthread_mutex_unlock(&fileLock);
94     return 0;
95   }
96
97   file = fopen(fileName, "r");
98   if (!file)
99   {
100     log->log("Config", Log::DEBUG, "Config error: Could not open config file");
101     pthread_mutex_unlock(&fileLock);
102     return 0;
103   }
104   return 1;
105 }
106
107 void Config::closeFile()
108 {
109   if (!initted) return;
110
111   fclose(file);
112   file = NULL;
113   pthread_mutex_unlock(&fileLock);
114 }
115
116 int Config::readLine()
117 {
118   if (!initted || !file) { log->log("Config", Log::DEBUG, "1"); return 0; }
119   if (!fgets(buffer, BUFFER_LENGTH-1, file)) { /*log->log("Config", Log::DEBUG, "2");*/ return 0; }
120   lastLineLength = strlen(buffer);
121 //  log->log("Config", Log::DEBUG, "buffer before trim: '%s'", buffer);
122   trim(buffer);
123 //  log->log("Config", Log::DEBUG, "buffer after trim: '%s'", buffer);
124   return 1;
125 }
126
127 // START HERE
128
129 FILE* Config::copyToHere(long position)
130 {
131   FILE* newFile = fopen(fileNameTemp, "w");
132
133   if (!newFile) return NULL;
134
135   long newPos = 0;
136   rewind(file);
137
138   while (newPos < position)
139   {
140     fgets(buffer, BUFFER_LENGTH-1, file);
141     fputs(buffer, newFile);
142     newPos += strlen(buffer);
143   }
144   return newFile;
145 }
146
147 int Config::copyRest(FILE* newFile)
148 {
149   if (newFile)
150   {
151     while(fgets(buffer, BUFFER_LENGTH-1, file))
152     {
153       fputs(buffer, newFile);
154     }
155
156     fclose(newFile);
157   }
158   fclose(file);
159   file = NULL;
160
161   if (newFile) rename(fileNameTemp, fileName);
162
163   pthread_mutex_unlock(&fileLock);
164   return 1;
165 }
166
167 int Config::deleteValue(const char* section, char* key)
168 {
169   if (!initted) return 0;
170   if (!openFile()) return 0;
171
172   if (!findSection(section))
173   {
174     closeFile();
175     log->log("Config", Log::DEBUG, "Config error: Section %s not found", section);
176     return 0;
177   }
178   if (!findKey(key))
179   {
180     closeFile();
181     log->log("Config", Log::DEBUG, "Config error: Key %s not found", key);
182     return 0;
183   }
184
185   FILE* newFile = copyToHere(ftell(file) - lastLineLength);
186   fgets(buffer, BUFFER_LENGTH-1, file);
187
188   return copyRest(newFile);
189 }
190
191 int Config::setValueLong(const char* section, char* key, long newValue)
192 {
193   char longBuffer[50];
194   sprintf(longBuffer, "%li", newValue);
195   return setValueString(section, key, longBuffer);
196 }
197
198 int Config::setValueLongLong(char* section, char* key, long long newValue)
199 {
200   char longBuffer[50];
201   sprintf(longBuffer, "%lli", newValue);
202   return setValueString(section, key, longBuffer);
203 }
204
205 int Config::setValueDouble(char* section, char* key, double newValue)
206 {
207   char doubleBuffer[50];
208   sprintf(doubleBuffer, "%f", newValue);
209   return setValueString(section, key, doubleBuffer);
210 }
211
212 int Config::setValueString(const char* section, const char* key, const char* newValue)
213 {
214   if (!initted) return 0;
215   if (!openFile()) return 0;
216
217   if (findSection(section))
218   {
219     if (findKey(key))
220     {
221       FILE* newFile = copyToHere(ftell(file) - lastLineLength);
222       if (!newFile)
223       {
224         closeFile();
225         log->log("Config", Log::DEBUG, "Config error: Could not write temp config file");
226         return 0;
227       }
228
229       fgets(buffer, BUFFER_LENGTH-1, file);
230       fprintf(newFile, "%s = %s\n", key, newValue);
231       return copyRest(newFile);
232     }
233     else
234     {
235       rewind(file);
236       findSection(section);
237       FILE* newFile = copyToHere(ftell(file));
238       if (!newFile)
239       {
240         closeFile();
241         log->log("Config", Log::DEBUG, "Config error: Could not write temp config file");
242         return 0;
243       }
244
245       fprintf(newFile, "%s = %s\n", key, newValue);
246       return copyRest(newFile);
247     }
248   }
249   else
250   {
251     // section not found
252     fseek(file, 0, SEEK_END);
253     FILE* newFile = copyToHere(ftell(file));
254     if (!newFile)
255     {
256       closeFile();
257       log->log("Config", Log::DEBUG, "Config error: Could not write temp config file");
258       return 0;
259     }
260
261     fprintf(newFile, "[%s]\n%s = %s\n", section, key, newValue);
262     return copyRest(newFile);
263   }
264 }
265
266 char* Config::getSectionKeyNames(const char* section, int& numberOfReturns, int& allKeysSize)
267 {
268   numberOfReturns = 0;
269   allKeysSize = 0;
270   char* allKeys = NULL;
271   int allKeysIndex = 0;
272   int keyLength;
273   char* equalspos;
274
275   if (!initted) return NULL;
276   if (!openFile()) return NULL;
277   if (!findSection(section)) return NULL;
278
279   char foundKey[BUFFER_LENGTH];
280
281   while(readLine())
282   {
283     // Is this line a section header? if so, exit
284     if ((buffer[0] == '[') && (buffer[strlen(buffer)-1] == ']')) break;
285
286     equalspos = strstr(buffer, "=");
287     if (!equalspos) continue;  // if there is no = then it's not a key
288     memcpy(foundKey, buffer, equalspos-buffer);
289     foundKey[equalspos-buffer] = '\0';
290     trim(foundKey);
291     keyLength = strlen(foundKey);
292     allKeysSize += keyLength + 1;
293     allKeys = (char*)realloc(allKeys, allKeysSize);
294     memcpy(&allKeys[allKeysIndex], foundKey, keyLength);
295     allKeysIndex += keyLength;
296     allKeys[allKeysIndex] = '\0';
297     allKeysIndex++;
298     numberOfReturns++;
299   }
300
301   closeFile();
302   return allKeys;
303 }
304
305
306 // END HERE
307
308 int Config::findSection(const char* section)
309 {
310   if (!initted || !file) return 0;
311   if (strlen(section) > (BUFFER_LENGTH-2))
312   {
313     log->log("Config", Log::DEBUG, "Config error: Section given exceeds max length");
314     return 0;
315   }
316
317   char toFind[BUFFER_LENGTH];
318   toFind[0] = '[';
319   toFind[1] = '\0';
320   strcat(toFind, section);
321   strcat(toFind, "]");
322
323   while(readLine())
324   {
325 //    log->log("Config", Log::DEBUG, "to find '%s' this line '%s'", toFind, buffer);
326     if (!strcmp(toFind, buffer)) return 1;
327   }
328   return 0;
329 }
330
331 int Config::findKey(const char* key)
332 {
333   if (!initted || !file) return 0;
334
335   if (strlen(key) > (BUFFER_LENGTH-1))
336   {
337     log->log("Config", Log::DEBUG, "Config error: Key given exceeds max length");
338     return 0;
339   }
340
341   char prepForTest[BUFFER_LENGTH];
342
343   // do a rough search first, this could match substrings that we don't want
344   while(readLine())
345   {
346     // Is this line a section header? if so, exit
347     if ((buffer[0] == '[') && (buffer[strlen(buffer)-1] == ']')) return 0;
348     if (strstr(buffer, key))
349     {
350       // rough search found match
351       char* equalspos = strstr(buffer, "=");
352       if (!equalspos) continue;
353       memcpy(prepForTest, buffer, equalspos-buffer);
354       prepForTest[equalspos-buffer] = '\0';
355       trim(prepForTest);
356
357       if (!strcmp(key, prepForTest))
358       {
359         // in buffer, set all up to equals to space, then trim!
360         for(char* curPos = buffer; curPos <= equalspos; curPos++)
361         {
362           *curPos = ' ';
363         }
364         trim(buffer);
365         return 1;
366       }
367     }
368   }
369   return 0;
370 }
371
372 char* Config::getValueString(const char* section, const char* key)
373 {
374   if (!initted) return NULL;
375   if (!openFile()) return NULL;
376
377   if (!findSection(section))
378   {
379     closeFile();
380     log->log("Config", Log::DEBUG, "Config error: Section %s not found", section);
381     return 0;
382   }
383   if (!findKey(key))
384   {
385     closeFile();
386     log->log("Config", Log::DEBUG, "Config error: Key %s not found", key);
387     return 0;
388   }
389
390   char* returnString = new char[strlen(buffer)+1];
391   strcpy(returnString, buffer);
392
393   closeFile();
394
395   return returnString;
396 }
397
398 long Config::getValueLong(const char* section, const char* key, int* failure)
399 {
400   *failure = 1;
401   if (!initted) return 0;
402   if (!openFile()) return 0;
403
404   if (!findSection(section))
405   {
406     closeFile();
407     log->log("Config", Log::DEBUG, "Config error: Section %s not found", section);
408     return 0;
409   }
410   if (!findKey(key))
411   {
412     closeFile();
413     log->log("Config", Log::DEBUG, "Config error: Key %s not found", key);
414     return 0;
415   }
416   *failure = 0;
417
418   char* check;
419   long retVal = strtol(buffer, &check, 10);
420   if ((retVal == 0) && (check == buffer)) *failure = 1;
421   closeFile();
422
423   return retVal;
424 }
425
426 long long Config::getValueLongLong(char* section, char* key, int* failure)
427 {
428   *failure = 1;
429   if (!initted) return 0;
430   if (!openFile()) return 0;
431
432   if (!findSection(section))
433   {
434     closeFile();
435     log->log("Config", Log::DEBUG, "Config error: Section %s not found", section);
436     return 0;
437   }
438   if (!findKey(key))
439   {
440     closeFile();
441     log->log("Config", Log::DEBUG, "Config error: Key %s not found", key);
442     return 0;
443   }
444   *failure = 0;
445
446   char* check;
447   long long retVal = strtoll(buffer, &check, 10);
448   if ((retVal == 0) && (check == buffer)) *failure = 1;
449   closeFile();
450
451   return retVal;
452 }
453
454 double Config::getValueDouble(char* section, char* key, int* failure)
455 {
456   *failure = 1;
457   if (!initted) return 0;
458   if (!openFile()) return 0;
459
460   if (!findSection(section))
461   {
462     closeFile();
463     log->log("Config", Log::DEBUG, "Config error: Section %s not found", section);
464     return 0;
465   }
466   if (!findKey(key))
467   {
468     closeFile();
469     log->log("Config", Log::DEBUG, "Config error: Key %s not found", key);
470     return 0;
471   }
472
473   *failure = 0;
474
475   char* check;
476   double retVal = strtod(buffer, &check);
477   if ((retVal == 0) && (check == buffer)) *failure = 1;
478
479   closeFile();
480
481   return retVal;
482 }
483
484
485
486 void Config::trim(char* str)
487 {
488   int pos, len, start, end;
489
490   // Kill comments
491   len = strlen(str);
492   for(pos = 0; pos < len; pos++)
493   {
494     if ((str[pos] == '#') || (str[pos] == ';'))
495     {
496       // Mod. If #/; is at start of line ok. Else, if it is after a space, ok.
497
498       if ((pos == 0) || (isspace(str[pos - 1])))
499       {
500         str[pos] = '\0';
501         break;
502       }
503
504     }
505   }
506
507   len = strlen(str);
508   end = len;
509   if (!len) return;
510
511   start = 0;
512   while(isspace(str[start])) start++;
513   while(isspace(str[end-1]))
514   {
515     end--;
516     if (end == 0)
517     {
518       str[0] = '\0';
519       return;
520     }
521   }
522   for(pos = start; pos < end; pos++) str[pos - start] = str[pos];
523   str[end - start] = '\0';
524 }